I have a Rails API using JWT for login. login works with the token generated and stored in local storage. However, having trouble authorizing controller actions based on decoding the token.
authorize_request is used as a before action in various controllers.
here is the authorize_request action as defined in the application_controller:
class ApplicationController < ActionController::API
def not_found
render json: { error: 'not_found' }
end
def authorize_request
header = request.headers['Authorization']
header = header.split(' ').last if header
puts "header is #{header}"
begin
@decoded = JsonWebToken.decode(header)
puts "decoded header is #{@decoded}"
@current_user = User.find(@decoded[:user_id])
puts "current_user is #{@current_user}"
rescue ActiveRecord::RecordNotFound => e
render json: { errors: e.message }, status: :unauthorized
rescue JWT::DecodeError => e
render json: { errors: e.message }, status: :unauthorized
end
end
end
Here is the JsonWebToken class decode method:
class JsonWebToken
SECRET_KEY = Rails.application.secrets.secret_key_base
def self.encode(payload, exp = 24.hours.from_now)
payload[:exp] = exp.to_i
JWT.encode(payload, SECRET_KEY)
end
def self.decode(token)
puts("decoding token: #{token}")
decoded = JWT.decode(token, SECRET_KEY)
puts("decoded is #{decoded}")
HashWithIndifferentAccess.new decoded
end
end
based on the puts stmts included, I can see that the token is decoded in the JWT class, but it is still not accessible in the controller:
header is eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiNjZiZmQyMDAtZDExMy00NjdlLTkwMmEtMDRjMmI5YjE2ZmUwIiwiZXhwIjoxNjgwNzAyMzExfQ.x95ikz4QeWAdgm2rak_L6eUOqhILsRIepvALGieAwx8
decoding token: eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiNjZiZmQyMDAtZDExMy00NjdlLTkwMmEtMDRjMmI5YjE2ZmUwIiwiZXhwIjoxNjgwNzAyMzExfQ.x95ikz4QeWAdgm2rak_L6eUOqhILsRIepvALGieAwx8
decoded is [{"user_id"=>"66bfd200-d113-467e-902a-04c2b9b16fe0", "exp"=>1680702311}, {"alg"=>"HS256"}]
decoded header is {}
JWT.decode(token, SECRET_KEY)
is returning an array, not a hash.
Passing an array to HashWithIndifferentAccess.new
is going to return an empty hash, which is what you are returning to the controller
Just find the array element with user_id and return that to the controller.