May 27, 2024
Devise header based token authentication
-
This is the approach we use for our hybrid mobile apps. It relies on a database-stored auth_token. This post doesn't cover expiring & refreshing the token or supporting multiple user sessions from different devices,
-
Setup
-
Add an auth_token method to the user model
-
# models/user.rb class User < ApplicationRecord has_secure_token :auth_token end -
Set up a new devise (warden) auth strategy
-
# config/initializers/warden.rb class AuthTokenStrategy < Warden::Strategies::Base def valid? auth_token.present? end def authenticate! user = User.find_by(auth_token: auth_token) if user success!(user) else fail!('Invalid email or password') end end def store? false end private def auth_token env['HTTP_AUTHORIZATION'].to_s.remove('Bearer ') end end Warden::Strategies.add(:auth_token, AuthTokenStrategy) -
Tell Devise to use the new strategy
-
Additionally, tell devise to skip session storage for this strategy
-
# initializers/devise.rb Devise.setup do |config| config.warden do |manager| manager.default_strategies(scope: :user).unshift :auth_token end config.skip_session_storage = [:http_auth,:auth_token] end -
Create an API endpoint that will return the auth_token on successful sign in
-
# controllers/api/v1/users_controller.rb def sign_in user = User.find_by(email: params[:email]) if user && user.valid_password?(params[:password]) user.regenerate_auth_token if user.auth_token.blank? render json: { user: { email: user.email, auth_token: user.auth_token } }, status: :ok else render json: { error: "Invalid password" }, status: :unauthorized end end -
Usage
-
On the client, hit the login endpoint and get and store the auth_token. Then on subsequent requests include an authorization header with the token.
-
const response = await fetch(url, { headers: { Authorization: `Bearer ${authToken}`, "X-Source": 'nifti-expo' } }); -
In your Rails app, use the auth helper methods as you normally would
-
class HomeController < ApplicationController before_action :authenticate_user! end -