Plugin System
How Custos plugins work and how to combine them
Plugin System
Every feature in Custos is a plugin. Plugins are registered modules that add methods, associations, and validations to your model when activated.
How Plugins Work
Each plugin is a Ruby module with an apply class method. When you call plugin :name inside a custos block, Custos:
- Looks up the plugin in the registry
- Calls
apply(model_class, **options)with any options you passed - The plugin includes instance methods, extends class methods, and sets up associations
module Custos
module Plugins
module Password
def self.apply(model_class, **options)
model_class.include(InstanceMethods)
model_class.extend(ClassMethods)
# set up validations based on options...
end
module InstanceMethods
def authenticate_password(plain_password)
# ...
end
end
module ClassMethods
def find_by_email_and_password(email:, password:)
# ...
end
end
end
end
end
Custos::Plugin.register(:password, Custos::Plugins::Password)Plugin Registry
All plugins are registered at load time via Custos::Plugin.register. You can inspect what's available:
Custos::Plugin.registered_names
# => [:password, :magic_link, :api_tokens, :mfa, :lockout, :email_confirmation, :remember_me]
Custos::Plugin.registered?(:password)
# => trueCombining Plugins
Plugins are independent. You can combine any number of them on a single model:
class User < ApplicationRecord
include Custos::Authenticatable
custos do
plugin :password
plugin :magic_link
plugin :mfa
plugin :lockout
plugin :email_confirmation
plugin :remember_me
end
endOr use a minimal set:
class ApiClient < ApplicationRecord
include Custos::Authenticatable
custos do
plugin :api_tokens
end
endPlugin Interactions
Some plugins are aware of each other:
- Password + Lockout: When both are enabled, the Password plugin automatically calls
record_failed_attempt!on failed authentication andreset_failed_attempts!on success. - All other combinations are fully independent.
Checking Enabled Plugins
You can query which plugins are active on a model:
User.custos_config.plugin_enabled?(:password)
# => true
User.custos_config.loaded_plugins
# => { password: {}, magic_link: {}, mfa: {} }Available Plugins
| Plugin | Description | Dependencies |
|---|---|---|
| Password | Email + password with Argon2 | argon2 gem |
| Magic Link | Passwordless email links | None |
| API Tokens | Bearer token auth | None |
| MFA | TOTP, backup codes, SMS | rotp gem |
| Lockout | Failed attempt lockout | None |
| Email Confirmation | Email verification | None |
| Remember Me | Persistent sessions | None |