Skip to content

Commit

Permalink
Refactor JWT token verification and decoding
Browse files Browse the repository at this point in the history
  • Loading branch information
komagata committed Dec 28, 2023
1 parent 4aeaae6 commit bc76d96
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 31 deletions.
37 changes: 20 additions & 17 deletions app/controllers/crazy_train/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,23 @@ class ApplicationController < ActionController::Base

def verify_token
@default_role = current_role
@role = if jwt_token && jwt_payload
jwt_payload['role'] || CrazyTrain.config.authenticated_role
else
CrazyTrain.config.unauthorized_role
end

payload_string = JSON.generate(jwt_payload)
CrazyTrain.setup_jwt_claims!(payload_string)

if bearer.nil?
@role = CrazyTrain.config.unauthorized_role
return
end

jwt = CrazyTrain::JWT.new(bearer)
jwt.decode!

@role =
if jwt.valid?
jwt.role || CrazyTrain.config.authenticated_role
else
CrazyTrain.config.unauthorized_role
end

CrazyTrain.setup_jwt_claims!(jwt.payload_string)
end

def setup_role
Expand All @@ -30,16 +39,10 @@ def teardown_role
switch_role(@default_role)
end

def jwt_token
request.headers['Authorization'].split.last
rescue StandardError
nil
end
private

def jwt_payload
CrazyTrain::JWT.decode(jwt_token, CrazyTrain.config.secret).first
rescue StandardError
nil
def bearer
request.headers['Authorization']&.sub(/^Bearer: /, '')
end
end
end
54 changes: 44 additions & 10 deletions lib/crazy_train/jwt.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,57 @@

module CrazyTrain
class JWT
HEADERS = { 'alg' => 'HS256', 'typ' => 'JWT' }.freeze
class << self
HEADERS = { 'alg' => 'HS256', 'typ' => 'JWT' }.freeze

def self.encode(payload, secret = CrazyTrain.config.secret)
::JWT.encode(payload, secret, 'HS256', HEADERS)
def encode(payload, secret = CrazyTrain.config.secret)
::JWT.encode(payload, secret, 'HS256', HEADERS)
end

def decode(token, secret = CrazyTrain.config.secret)
::JWT.decode(token, secret, true, HEADERS)
end

def generate_jwt_secret
SecureRandom.alphanumeric(32)
end
end

attr_reader :raw_token,
:secret,
:raw_header,
:raw_payload,
:raw_signeture,
:header,
:payload,
:signeture

def initialize(raw_token, secret = CrazyTrain.config.secret)
@raw_token = raw_token
@secret = secret
@header = nil
@payload = nil
@signeture = nil

@raw_header, @raw_payload, @raw_signeture = @raw_token.split('.') if raw_token
end

def parse!; end

def decode!
@payload, @header = CrazyTrain::JWT.decode(@raw_token, @secret)
end

def self.decode(token, secret = CrazyTrain.config.secret)
::JWT.decode(token, secret, true, HEADERS)
def role
payload.fetch('role', nil)
end

def self.generate_token(payload_string)
payload = JSON.parse(payload_string || '{}')
encode(payload)
def valid?
@header && @payload
end

def self.generate_jwt_secret
SecureRandom.alphanumeric(32)
def payload_string
JSON.generate(@payload)
end
end
end
3 changes: 2 additions & 1 deletion lib/tasks/crazy_train.rake
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ require 'crazy_train'

namespace :crazy_train do
task generate_token: :environment do
puts CrazyTrain::JWT.generate_token(ENV.fetch('PAYLOAD', nil))
payload = ENV.fetch('PAYLOAD', nil)
puts CrazyTrain::JWT.encode(payload)
end
end
13 changes: 10 additions & 3 deletions test/crazy_train/jwt_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
module CrazyTrain
class JWTTest < ActiveSupport::TestCase
setup do
@payload = { 'iss' => 'crazy_train' }.freeze
@headers = { 'alg' => 'HS256', 'typ' => 'JWT' }.freeze
@secret = 'a' * 32
@token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJjcmF6eV90cmFpbiJ9.tUAwhK5t_UOqDLubyZg1fEt4Vl-w4pyur6vrdSjqiBI'
@payload = { 'iss' => 'crazy_train' }.freeze
@secret = '0123456789'
@token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJjcmF6eV90cmFpbiJ9.a-9Uf4KIyYpOIGODLc5pXP2bY3DHQ-lNtmE-RK8sWgo'
end

test '.encode' do
Expand All @@ -21,5 +21,12 @@ class JWTTest < ActiveSupport::TestCase
assert_equal @payload, payload
assert_equal @headers, headers
end

test '.decode!' do
jwt = ::CrazyTrain::JWT.new(@token, @secret)
jwt.decode!

assert_equal @payload, jwt.payload
end
end
end

0 comments on commit bc76d96

Please sign in to comment.