Devise Token Auth

repository·master·Indexed 25 days ago

https://github.com/lynndylanhurley/devise_token_auth

A Rails gem providing secure, multi-client, token-based authentication designed for APIs used by SPAs and mobile applications. It features token rotation, multi-client session support, and integration with OAuth2 via OmniAuth. The library includes generators for ActiveRecord and Mongoid, and provides endpoints for sign-in, registration, account management, and password resets.

Tokens
14.4K
Snippets
37
Records
69
Agent score
83%

What's inside devise_token_auth

  1. Overview of Devise Token Auth

    master

    Devise Token Auth provides simple, multi-client, and secure token-based authentication for Rails applications. It is specifically designed for Single Page Applications (SPAs) or mobile apps where token-based authentication is required instead of cookies.

    Key features include:

    • Token Refreshing: Tokens are refreshed on each request and expire quickly to enhance security.
    • Multi-client Support: Maintains separate sessions for each client/device, allowing multiple concurrent sessions per user.
    • Integration: Works with various client-side libraries including ng-token-auth (AngularJS), Angular-Token (Angular), redux-token-auth (React/Redux), jToker (jQuery), vanilla-token-auth, and flutter_token_auth (Flutter).
    • Authentication Methods: Supports OAuth2 via OmniAuth and email-based authentication via Devise (covering registration, login, logout, password resets, and account confirmation).
    • Multiple Models: Supports authentication across multiple user models.
  2. Security features of Devise Token Auth

    master

    Devise Token Auth implements several security measures by default to protect authentication tokens:

    • Token Rotation: Tokens are changed after every request to mitigate replay attacks.
    • Cryptographic Strength: Tokens are generated using cryptographically secure random number generators.
    • Hashing: Tokens are hashed using BCrypt and are never stored in plain-text.
    • Timing Attack Protection: Tokens are compared using secure comparison techniques to prevent timing attacks.
    • Token Expiration: Tokens are invalidated after 2 weeks, requiring users to re-authenticate.

    Critical Requirement: You must use HTTPS to ensure tokens are not intercepted in transit. The gem does not manage transport layer security.

  3. Understand token management and rotation

    master

    By default, devise_token_auth implements a strict token rotation policy. After every successful API request, the current access-token is invalidated and a new one is generated.

    To maintain a valid session, the client must extract the new token from the access-token header of the response and include it in the access-token header of the subsequent request. If a client attempts to reuse an old token that has already been invalidated by a previous successful request, the request will fail.

  4. Add custom parameters to sign up and account update

    master

    To allow additional parameters during registration or account updates, override the DeviseTokenAuth::RegistrationsController and use the configure_permitted_parameters method to permit the new keys via the devise_parameter_sanitizer.

    class RegistrationsController < DeviseTokenAuth::RegistrationsController
      before_action :configure_permitted_parameters
    
      protected
    
      def configure_permitted_parameters
        devise_parameter_sanitizer.permit(:sign_up, keys: %i(name))
        devise_parameter_sanitizer.permit(:account_update, keys: %i(name))
      end
    end
  5. Disable OAuth authentication and routes

    master

    To completely disable OAuth authentication, you must perform two steps:

    1. Remove the :omniauthable module from the devise block in your User model.
    2. Instruct the routes to skip mounting the omniauth_callbacks controller in config/routes.rb using the skip option in mount_devise_token_auth_for.
    # 1. app/models/user.rb
    class User < ActiveRecord::Base
      # omit :omniauthable here
      devise :database_authenticatable, :confirmable,
             :recoverable, :trackable, :validatable,
             :registerable
    
      include DeviseTokenAuth::Concerns::User
    end
    
    # 2. config/routes.rb
    Rails.application.routes.draw do
      mount_devise_token_auth_for 'User', at: 'auth', skip: [:omniauth_callbacks]
    end
  6. Override built-in Devise Token Auth controllers

    master

    You can replace the default behavior of Devise Token Auth controllers by creating custom controllers that inherit from the library's base controllers.

    To implement an override:

    1. Create a new controller inheriting from the specific DeviseTokenAuth controller (e.g., DeviseTokenAuth::TokenValidationsController).
    2. Implement the desired action (e.g., validate_token).
    3. Register the custom controller in config/routes.rb using the controllers option within mount_devise_token_auth_for.

    Note: @resource is automatically set by the set_user_by_token concern in applicable controllers.

    # config/routes.rb
    Rails.application.routes.draw do
      mount_devise_token_auth_for 'User', at: 'auth', controllers: {
        token_validations:  'overrides/token_validations'
      }
    end
    
    # app/controllers/overrides/token_validations_controller.rb
    module Overrides
      class TokenValidationsController < DeviseTokenAuth::TokenValidationsController
    
        def validate_token
          # @resource will have been set by set_user_by_token concern
          if @resource
            render json: {
              data: @resource.as_json(methods: :calculate_operating_thetan)
            }
          else
            render json: {
              success: false,
              errors: ["Invalid login credentials"]
            }, status: 401
          end
        end
      end
    end
  7. Configure Action Mailer for email authentication

    master

    To use email authentication, your Rails application must be configured to send emails via Action Mailer. For local development, it is recommended to use mailcatcher.

    Example configuration for using Mailcatcher in your development environment:

    # config/environments/development.rb
    Rails.application.configure do
      config.action_mailer.default_url_options = { host: 'your-dev-host.dev' }
      config.action_mailer.delivery_method = :smtp
      config.action_mailer.smtp_settings = { address: 'your-dev-host.dev', port: 1025 }
    end
  8. Use separate ApplicationControllers for Devise and ActiveAdmin

    master

    If you are using ActiveAdmin, it extends from your app's ApplicationController. Including DeviseTokenAuth::Concerns::SetUserByToken in your main ApplicationController can cause conflicts.

    To resolve this, create a dedicated ApiController for your API routes and keep the standard ApplicationController for ActiveAdmin and other non-API routes.

    # app/controllers/api_controller.rb
    # API routes extend from this controller
    class ApiController < ActionController::Base
      include DeviseTokenAuth::Concerns::SetUserByToken
    end
    
    # app/controllers/application_controller.rb
    # leave this for ActiveAdmin, and any other non-api routes
    class ApplicationController < ActionController::Base
    end
  9. Install Devise Token Auth via Rails Generator

    master

    Use the Rails generator to perform a one-step installation. This will create an initializer, update your model, append routes, and include necessary controller concerns.

    For standard ActiveRecord usage:

    rails g devise_token_auth:install [USER_CLASS] [MOUNT_PATH]

    For Mongoid usage:

    rails g devise_token_auth:install_mongoid [USER_CLASS] [MOUNT_PATH]

    Arguments:

    • USER_CLASS: The name of the class to use for user authentication (defaults to User).
    • MOUNT_PATH: The path at which to mount the authentication routes (defaults to auth).

    Example:

    rails g devise_token_auth:install User auth
    rails g devise_token_auth:install User auth
  10. Configure Devise ORM and Mailer settings

    master

    You can configure standard Devise settings by creating config/initializers/devise.rb.

    Key tasks include:

    • Setting the mailer_sender address.
    • Loading the ORM (e.g., :active_record or :mongoid).
    • Configuring navigational_formats (e.g., setting to [:json] when using rails-api to avoid ActionDispatch::Flash middleware issues).
    Devise.setup do |config|
      # The e-mail address that mail will appear to be sent from
      config.mailer_sender = "support@myapp.com"
    
      # ==> ORM configuration
      require 'devise/orm/active_record'
    
      # If using rails-api, tell devise to not use ActionDispatch::Flash
      # middleware b/c rails-api does not include it.
      config.navigational_formats = [:json]
    end
  11. Add a second authentication model

    master

    To support multiple user models (e.g., User and Admin), follow these steps:

    1. Generate the new model: Run the devise_token_auth:install generator for the new model. This creates the model and sets up authentication routes with a base path.

      rails g devise_token_auth:install Admin admin_auth
    2. Configure Routes: Because controllers default to the first available Devise mapping, you must wrap routes for subsequent models within a devise_scope block to ensure they authorize requests using the correct class.

    3. Restrict Controllers: Once configured, the new model's controllers will have access to specific authentication methods based on the model name (e.g., authenticate_admin!, current_admin, and admin_signed_in?).

    rails g devise_token_auth:install Admin admin_auth