Custos

Overview

Plugin-based authentication for Ruby on Rails applications

Custos

Custos is a plugin-based authentication library for Ruby on Rails. It draws inspiration from Rodauth for its modular plugin architecture and from Devise for its per-model configuration style.

Why Custos?

Most Rails authentication libraries either give you everything at once (Devise) or require you to build from scratch (hand-rolled). Custos takes a different approach:

  • Only what you need. Each feature is a standalone plugin. Use password authentication for users and API tokens for service accounts -- on the same app.
  • Per-model configuration. Different models can have completely different authentication strategies.
  • No magic controllers. Custos provides services and helpers, not generated controllers and routes. You stay in control.
  • Bring your own mailer. Email delivery is handled through callbacks. Use Action Mailer, Postmark, or anything else.

Quick Example

class User < ApplicationRecord
  include Custos::Authenticatable

  custos do
    plugin :password
    plugin :magic_link
    plugin :mfa
    plugin :lockout
    plugin :email_confirmation
    plugin :remember_me

    on(:magic_link_created) do |record, token|
      AuthMailer.magic_link(record, token).deliver_later
    end

    on(:email_confirmation_requested) do |record, token|
      AuthMailer.confirm_email(record, token).deliver_later
    end
  end
end
class ApiClient < ApplicationRecord
  include Custos::Authenticatable

  custos do
    plugin :api_tokens
  end
end

Available Plugins

PluginDescription
PasswordEmail + password authentication with Argon2 hashing
Magic LinkPasswordless authentication via email links
API TokensBearer token authentication for APIs
MFATOTP, backup codes, and SMS verification
LockoutAccount lockout after failed attempts
Email ConfirmationEmail verification on sign-up
Remember MeLong-lived sessions via persistent tokens

Requirements

  • Ruby 3.2+
  • Rails 7.0+
  • Bundler

Security

Custos is built with security as the top priority:

  • Argon2id for password hashing (resistant to GPU/ASIC attacks)
  • HMAC-SHA256 token digests stored in the database; plain-text tokens are never persisted
  • Timing-safe comparisons via ActiveSupport::SecurityUtils.secure_compare
  • Encrypted MFA secrets using AES-256-GCM (via Custos::MfaEncryptor)
  • 256-bit entropy session tokens (SecureRandom.urlsafe_base64(32))

On this page