Having an issue with getting JWT token using devise gem
and devise-jwt gem
. This is how my confirmation looks like.
devise.rb
Devise.setup do |config|
config.jwt do |jwt|
jwt.secret = SECRETS.devise_jwt_secret_key
jwt.dispatch_requests = [ ['POST', %r{^/authentication_tokens/create$}] ]
end
end
user.rb
class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:jwt_authenticatable, jwt_revocation_strategy: Devise::JWT::RevocationStrategies::Null
end
authentication_tokens_controller.rb
class Api::V1::AuthenticationTokensController < Devise::SessionsController
include Devise::Controllers::Helpers
skip_before_action :verify_authenticity_token
prepend_before_action :require_no_authentication, only: [:create]
before_action :rewrite_param_names, only: [:create]
def new
render json: { response: "Authentication required" }, status: 401
end
def create
self.resource = warden.authenticate!(auth_options)
sign_in(resource_name, resource)
yield resource if block_given?
render json: {success: true, jwt: current_token, response: "Authentication successful" }
end
private
def rewrite_param_names
request.params[:user] = {email: request.params[:email], password: request.params[:password]}
end
def current_token
request.env['warden-jwt_auth.token']
end
end
routes.rb
get 'home#secret'
devise_for :users
resources :tasks
#other routes for the website removed for brevity
namespace :api, defaults: { format: :json } do
namespace :v1 do
resources :users
devise_scope :user do
post '/authentication_tokens/create', to: "authentication_tokens#create"
end
end
end
For some reason request.env['warden-jwt_auth.token']
returns null
all the time, however, the user is authenticated.
Is there anything that I need to add to get the JWT token when a user signs in?
Update - routes and namespacing
After days of debugging, I believe I have found the source of my problem. My app has a frontend which uses normal routes. The code above doesn't work however if I do something like the code below. All is good.
scope :api, defaults: {format: :json} do
devise_for :users, controllers: {sessions: 'v1/authentication_tokens'}
end
Is there a way of namespacing the devise_for
for me API even though it has been used above for the website?
You just need to make your route RESTful.
routes.rb
post '/authentication_tokens', to: "authentication_tokens#create"
devise.rb
config.jwt do |jwt|
jwt.secret = SECRETS.devise_jwt_secret_key
jwt.dispatch_requests = [ ['POST', %r{^/authentication_tokens$}] ]
end
I've briefly looked on your issue and, it's probably wrong, but something for you to give a try:
looking on the following lines
def create
self.resource = warden.authenticate!(auth_options)
end
def current_token
request.env['warden-jwt_auth.token']
end
If you say that user is being authenticated even with nil
returned from current_token
method, so that means that jwt is passing correctly, but your way of fetching it is wrong.
Try to debug self.resource = warden.authenticate!(auth_options)
line and see what contains inside auth_options
, probably you can take JWT from there, or you just trying to get warden-jwt_auth.token
in a wrong way. Try to debug this line as well and see if you should probably take "warden-jwt_auth.token" from request.headers["warden-jwt_auth.token"]
, or something like this. Just print out the whole response of your request and search by needed header.
I hope this helps!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With