Passwordless Ruby on Rails Engine

repository·master·Indexed 23 days ago

https://github.com/mikker/passwordless

A Ruby on Rails engine providing magic link and token-based authentication to allow users to sign in without passwords. It includes features for custom user model integration, route constraints, configurable token generation, and test helpers for RSpec and TestUnit.

Tokens
5.6K
Snippets
15
Records
39
Agent score
79%

What's inside Passwordless

  1. Security considerations for passwordless authentication

    master

    While passwordless authentication is generally as secure as traditional username/password combinations, the primary security risk lies in your email delivery service.

    If your email provider account is compromised, an attacker may gain access to the logs of sent emails, effectively compromising all users. To mitigate this risk:

    • Configure your email provider to avoid logging sent emails.
    • Enable non-SMS 2-factor authentication (2FA) for your email provider account.
  2. Override Passwordless views

    master

    To customize the appearance of the authentication forms and emails, you can override the default templates. You can generate the default views into your application using:

    rails generate passwordless:views

    Key view paths to override:

    • Email input form: app/views/passwordless/sessions/new.html.erb
    • Token input form: app/views/passwordless/sessions/show.html.erb
    • Sign-in email: app/views/passwordless/mailer/sign_in.text.erb
    rails generate passwordless:views
  3. Upgrade your database schema for Passwordless 1.0+

    master

    If you are upgrading from a version prior to 1.0, you must update your database schema to support encrypted tokens, UUID identifiers, and the removal of PII (Personally Identifiable Information).

    Run the following command to generate a migration:

    bin/rails g migration UpgradePasswordless

    Then, implement the following changes in the migration file:

    • Add token_digest (string) to passwordless_sessions and index it.
    • Remove the token column from passwordless_sessions.
    • Add identifier (string) to passwordless_sessions and add a unique index.
    • Remove user_agent and remote_addr columns from passwordless_sessions.
    class UpgradePasswordless < ActiveRecord::Migration[7.0]
      def change
        # Encrypted tokens
        add_column(:passwordless_sessions, :token_digest, :string)
        add_index(:passwordless_sessions, :token_digest)
        remove_column(:passwordless_sessions, :token, :string, null: false)
        # UUID
        add_column(:passwordless_sessions, :identifier, :string)
        add_index(:passwordless_sessions, :identifier, unique: true)
    
        # Remove PII
        remove_column(:passwordless_sessions, :user_agent, :string, null: false)
        remove_column(:passwordless_sessions, :remote_addr, :string, null: false)
      end
    end
  4. Implement current_user and access control

    master

    Passwordless does not automatically provide a current_user helper. To implement it, include Passwordless::ControllerHelpers in your ApplicationController, define a current_user method that uses authenticate_by_session(User), and make it a helper_method.

    To protect routes, you can use a require_user! method. If you want to redirect users back to their intended destination after they sign in, call save_passwordless_redirect_location!(User) before redirecting them to the sign-in page.

    class ApplicationController < ActionController::Base
      include Passwordless::ControllerHelpers
    
      # ...
    
      helper_method :current_user
    
      private
    
      def current_user
        @current_user ||= authenticate_by_session(User)
      end
    
      def require_user!
        return if current_user
        save_passwordless_redirect_location!(User)
        redirect_to root_path, alert: "You are not worthy!"
      end
    end
  5. Install Passwordless

    master

    To add Passwordless to your Rails application, add the gem to your Gemfile and run the engine installation command to copy the necessary migrations.

    $ bundle add passwordless
    $ bin/rails passwordless_engine:install:migrations
  6. Use test helpers for RSpec or TestUnit

    master

    Passwordless provides test helpers to simplify authentication testing in controller, request, and system tests.

    To enable these helpers:

    • For RSpec: Add require "passwordless/test_helpers" to your spec/rails_helper.rb.
    • For TestUnit: Add require "passwordless/test_helpers" to your test/test_helper.rb.

    Once required, you can use the following methods in your tests:

    # Available test methods:
    passwordless_sign_in(user) # signs you in as a user
    passwordless_sign_out      # signs out user
  7. Update routes for the un-isolated namespace

    master

    Passwordless no longer isolates its namespace. When upgrading to 1.0+, you must update your route helpers:

    1. Change scoped links like users.sign_in_path to the flat version users_sign_in_path.
    2. Remove main_app. prefixes from links (e.g., change main_app.whatever_path to whatever_path).
  8. Customize token delivery method

    master

    By default, Passwordless sends emails. You can override this behavior using the after_session_save callback in your configuration to send tokens via other channels like SMS.

    Passwordless.configure do |config|
      config.after_session_save = lambda do |session, request|
        # Example: Send via SMS instead of email
        # SmsApi.send_sms(session.authenticatable.phone_number, session.token)
      end
    end