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
endclass ApiClient < ApplicationRecord
include Custos::Authenticatable
custos do
plugin :api_tokens
end
endAvailable Plugins
| Plugin | Description |
|---|---|
| Password | Email + password authentication with Argon2 hashing |
| Magic Link | Passwordless authentication via email links |
| API Tokens | Bearer token authentication for APIs |
| MFA | TOTP, backup codes, and SMS verification |
| Lockout | Account lockout after failed attempts |
| Email Confirmation | Email verification on sign-up |
| Remember Me | Long-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))