Authentication
Lean CMS owns the authentication flow. Login, password reset, and magic-link
account setup are served from the gem at /lean-cms/login,
/lean-cms/reset-password, and /lean-cms/setup-password/:token. Your app
provides the User model; the gem provides everything else.
URLs
| Path | Purpose |
|---|---|
GET /lean-cms/login |
Login form |
POST /lean-cms/login |
Submit credentials |
DELETE /lean-cms/login |
Sign out |
GET /lean-cms/reset-password |
Forgot-password form |
POST /lean-cms/reset-password |
Send reset email |
GET /lean-cms/reset-password/:token/edit |
Set new password via signed token |
GET /lean-cms/setup-password/:token |
Magic-link account setup (new invitations and admin-triggered resets) |
URL helpers are namespaced: lean_cms_new_session_path,
lean_cms_new_password_path, lean_cms_password_setup_path, etc.
Including the concern
Add include LeanCms::Authentication to your ApplicationController:
class ApplicationController < ActionController::Base
include LeanCms::Authentication
# …
end
This installs before_action :require_authentication globally, plus the
authenticated?, current_user, start_new_session_for, and
terminate_session helpers. Public-facing controllers should opt out per
action or wholesale:
class PagesController < ApplicationController
allow_unauthenticated_access
end
class CheckoutController < ApplicationController
allow_unauthenticated_access only: :pricing
end
What the User model must provide
The gem stores LeanCms.user_class.constantize and calls these methods on it:
| Class method | Used by |
|---|---|
authenticate_by(email_address:, password:) |
LeanCms::SessionsController#create — provided automatically by has_secure_password. |
find_by(email_address:) |
LeanCms::PasswordsController#create |
find_by_password_reset_token!(token) |
LeanCms::PasswordsController#edit/update — provided by has_secure_password reset_token: true (default in Rails 8). |
| Instance method | Used by |
|---|---|
active? |
Sessions controller — deactivated users cannot log in. |
must_change_password? |
Sessions controller — forces password reset on next login. |
record_login! |
Called after successful login. |
has_any_cms_permission? |
LeanCms::Authorization — gates /lean-cms/* admin routes. |
can_edit_pages?, can_edit_blog?, can_manage_users?, can_access_settings? |
Specific admin areas. |
(Lean CMS does not require has_many :sessions or has_many :magic_links on User — it uses LeanCms::Session and LeanCms::MagicLink directly. That keeps it compatible with Rails 8’s built-in auth, which already defines has_many :sessions on its generated User.)
Minimum schema for the host users table:
create_table :users do |t|
t.string :email_address, null: false
t.string :password_digest, null: false
t.string :name
t.boolean :active, default: true, null: false
t.boolean :must_change_password, default: false, null: false
t.datetime :last_login_at
# Permission flags
t.boolean :is_super_admin, default: false
t.boolean :can_edit_pages, default: false
t.boolean :can_edit_blog, default: false
t.boolean :can_manage_users, default: false
t.boolean :can_access_settings, default: false
t.timestamps
t.index :email_address, unique: true
end
And the model:
class User < ApplicationRecord
has_secure_password
# … your permission predicates here (see installation guide) …
end
Sessions
LeanCms::Session is a thin Rails 8 session record (id, user reference,
ip_address, user_agent, timestamps). Sessions are tied to a signed
session_id cookie set on login and destroyed on logout. They live in the
lean_cms_sessions table.
To force-log-out a user (e.g. on deactivation), destroy their sessions
through LeanCms::Session directly:
LeanCms::Session.where(user: user).destroy_all
(Lean CMS deliberately does not require a has_many :sessions association
on User — that would collide with Rails 8 auth’s built-in has_many :sessions.)
Magic links
LeanCms::MagicLink powers two flows:
- Invitations — when a new user is created, send them a magic link to set their password and activate their account.
- Admin-triggered password resets — admins can issue a password-reset link for any user from the CMS users page.
magic_link = LeanCms::MagicLink.create_for_invitation(user)
LeanCms::UsersMailer.invitation(user, magic_link).deliver_later
magic_link = LeanCms::MagicLink.create_for_password_reset(user)
LeanCms::UsersMailer.admin_triggered_password_reset(user, magic_link).deliver_later
Magic links are single-use, expire (invitations: 24h, resets: 2h), and are invalidated when used.
Logged-in detection in views
Inside any view, current_user is available. To show admin chrome only when
the user has CMS access:
<% if current_user&.has_any_cms_permission? %>
<div class="admin-bar">…</div>
<% end %>