Sessions & devices
RailsFast ships with the sessions gem wired in by default, giving every app a GitHub-style security layer on top of Devise:
- A "Sessions & devices" page at
/settings/sessions: users see every device they're signed in on ("Chrome 137 on macOS", "MyApp 1.2 on Pixel 8"), can sign out any single device remotely, or sign out everywhere else with one click. - A login-activity trail: an append-only record of every login — successful and failed — plus logouts and revocations, with parsed device info and approximate location.
- An admin Security section in Madmin: a platform-wide device registry with per-device revoke, a per-user security panel on each user page, and the login trail — your first stop in any brute-force or account-takeover triage.
- Security emails out of the box: a "was this you?" email on the first sign-in from a never-seen device, and a "someone is trying to get into your account" email when an identity crosses 5 failed logins in 15 minutes (sent once at the crossing — never per attempt).
- A step-up reauthentication gate: revoking sessions is a sensitive action, so RailsFast asks for the user's password again unless they've confirmed it in the last 15 minutes (
app/controllers/concerns/recent_authentication.rb).
Everything is configured in config/initializers/sessions.rb — the file documents each decision inline. The user-facing views are ejected to app/views/sessions/ so you can restyle them like any other template view.
How liveness works (worth understanding)
One session row = one signed-in device. Liveness is explicit lifecycle state (sessions.ended_at / ended_reason) — the gem never infers auth state from a missing row, and tracking failures can never log anyone out ("tracking never breaks login" is the gem's #1 rule). Revoking a device ends its row; that device is signed out on its next request, and its long-lived remember-me cookie is rotated too — which is what makes the native apps' 1-year sessions actually revocable.
For the full API (user.sessions.live, session.revoke!, user.revoke_all_sessions!, custom hooks), the sessions README is the source of truth.
Housekeeping
SessionsSweepJob runs daily (see config/recurring.yml): it purges trail events past the 12-month retention window and evicts sessions beyond the per-user cap. No idle timeouts are configured by default — RailsFast never silently shortens anyone's session.
Hotwire Native awareness
Native app sessions are first-class: the WebView user agent convention (MyApp/1.2 (Pixel 8; Android 16; build 14); MyApp Android; RailsFast Native Android;) and the native HTTP clients' X-Client-* headers let the registry show real app versions, builds, and device models instead of "unknown browser". This works out of the box with the RailsFast Native shells — and if you never build a native app, the sessions feature works exactly the same for plain web browsers.
IP geolocation (trackdown)
Session locations (and the signup_country / signup_city columns on users) come from the trackdown gem, which is part of the default template. In production behind Cloudflare it's zero-config and free: Cloudflare's CF-IPCountry / geo headers answer synchronously. Optionally, you can configure a MaxMind database for richer offline lookups (BYOK — see the trackdown README). In development there are usually no Cloudflare headers, so locations simply stay blank — that's expected.