I'm building a Rails API and am trying to implement authentication using Devise. My goal is to use JWT tokens for authentication, but I'm encountering issues with the sign-in process and generating/responding with tokens.
I've overridden the Devise::SessionsController to handle JSON requests and respond with JWT tokens upon successful authentication. However, I'm facing a NoMethodError
with users_url
during the sign-in process, likely due to Devise attempting to redirect, which is not applicable for API responses.
NoMethodError at /api/v1/users/sign_in
======================================
undefined method `users_url' for #<Api::V1::SessionsController:0x000000000587f0>
> To access an interactive console with this error, point your browser to: /__better_errors
Here's how I've currently set up my Api::V1::SessionsController:
class Api::V1::SessionsController < Devise::SessionsController
respond_to :json
skip_before_action :verify_signed_out_user, only: :destroy
def create
self.resource = warden.authenticate!(auth_options)
if resource
token = generate_jwt_token(resource)
render json: { user: resource.as_json, token: token }, status: :created
else
render json: { error: 'Invalid email or password' }, status: :unauthorized
end
end
private
def generate_jwt_token(user)
# :)
end
end
devise.rb
# frozen_string_literal: true
Devise.setup do |config|
config.mailer_sender = 'info@example.com'
require 'devise/orm/mongoid'
config.case_insensitive_keys = [:email]
config.strip_whitespace_keys = [:email]
config.skip_session_storage = [:http_auth, :params_auth]
config.stretches = Rails.env.test? ? 1 : 12
config.reconfirmable = true
config.expire_all_remember_me_on_sign_out = true
config.password_length = 8..128
config.email_regexp = /\A[^@\s]+@[^@\s]+\z/
config.reset_password_within = 6.hours
config.sign_out_via = :delete
config.responder.error_status = :unprocessable_entity
config.responder.redirect_status = :see_other
config.navigational_formats = ['*/*', :html, :json]
config.jwt do |jwt|
jwt.secret = Rails.application.credentials.devise_jwt_secret_key
jwt.expiration_time = 1.day.to_i
end
end
Questions:
How can I properly implement the sign-in process in Api::V1::SessionsController
to avoid redirection attempts by Devise and ensure it's suitable for API use?
What's the best practice for generating and handling JWT tokens with Devise for Rails API authentication?
How should I structure the JSON response for sign-in and sign-out actions to make it more consumable by the front end?
Any advice on correctly setting up Devise for API authentication or pointing out what I might be missing would be greatly appreciated!
I would strongly advise against building your own auth system.
Since you are already using Devise, I would suggest using https://github.com/waiting-for-dev/devise-jwt
devise-jwt is a Devise extension which uses JWT tokens for user authentication. It follows secure by default principle.