Rails Authentication in 2025: What Actually Changed and Why It Matters
December 07, 2025
·By GGG
For about fifteen years, the answer to “how do I add auth to my Rails app?” was basically “just use Devise.” That changed in November 2024.
Rails 8 shipped with a built-in authentication generator, and suddenly we’re all re-evaluating decisions we used to make on autopilot. I’ve spent the last few months digging into the three real options we have now—Rails 8’s generator, Devise, and Rodauth—and here’s what I’ve found.
The Rails 8 Generator: DHH’s Teaching Moment
Let’s be clear about what rails generate authentication actually is. It’s not trying to be Devise. DHH said as much in the original GitHub issue: the goal is to “illuminate the basic path” for developers who know Rails has all the pieces for auth but aren’t sure how to wire them together.
Run the generator and you get about 52 lines of actual authentication logic in an Authentication concern. Plus a User model with has_secure_password, a Session model for database-backed tokens, controllers, views, migrations—the works. It’s readable code that you own completely.
What’s interesting is the database-backed session approach. Every login creates a record with the user’s IP and user agent. DHH’s reasoning: “Then you can do session indexes, alert when new sessions are created from unknown locations, do statistics on user agents.” This is actually more than Devise’s trackable module gives you, which only stores the most recent login.
The generator also uses authenticate_by (Rails 7.1+) which prevents timing attacks, and includes rate limiting out of the box—10 requests per 3 minutes on login attempts.
Here’s what it deliberately doesn’t include:
- No user registration — DHH argues these are “usually bespoke to each application”
- No email confirmation
- No 2FA — “Do not expect magic links or passkeys or 2FA”
- No social login
- No account lockout
Password reset is clever though—uses signed tokens with 15-minute expiration that don’t require database storage.
The community response has been positive but realistic. One dev who migrated from Devise said they finished in about two hours and noted: “I’ll never be afraid of Devise messing up my bundle update rails.” The missing signup flow remains a sticking point—several PRs trying to add registration have been closed.
Devise: Still Here, Still Massive
Let’s look at the numbers. Devise 4.9.4 (April 2024) powers over 568,000 public repositories. 258 million total downloads. 24.3k GitHub stars. 572 contributors. It’s not going anywhere.
The modular system is genuinely useful:
- Database Authenticatable — the basics
- Omniauthable — OmniAuth integration for social login
- Confirmable — email verification
- Recoverable — password resets
- Registerable — signup flow
- Rememberable — “remember me” cookies
- Trackable — sign-in stats
- Timeoutable — session expiration
- Validatable — email/password validation
- Lockable — account lockout after failed attempts
You enable what you need, ignore what you don’t. Setting up full auth with email confirmation, social login, and account security takes maybe an hour if you’ve done it before.
The ecosystem is deep. 804 gems depend on Devise. Need 2FA? devise-two-factor. JWT for APIs? devise-jwt. Passkeys? devise-passkeys. Multiple user types with separate auth flows? Native support.
But there are real frustrations that came into focus in 2024-2025:
Rails upgrade lag is real. Hotwire/Turbo support arrived 15 months after Rails 7.0 shipped. That’s a long time to be working around compatibility issues.
The magic fights back. Devise abstractions speed up initial development, but the moment you need something non-standard, you’re reading through Warden middleware code wondering where your request went.
API-only apps hit friction. Devise defaults to cookie sessions. Token auth requires bolting on additional gems.
Rails 8 compatibility has quirks. You might need Devise.reload_routes = false in your initializer if you’re seeing routing conflicts with ActionCable. There’s an open issue (#5752) about test environment problems with serialize_from_session.
Devise’s own README still says: “If you are building your first Rails application, we recommend you do not use Devise.” That’s been there for years, but it hits different now that Rails has an alternative.
Rodauth: The Security-First Option Nobody Talks About
Rodauth is the interesting third option that doesn’t get enough attention in the Rails world. Created by Jeremy Evans—Ruby Hero, Ruby committer, Sequel creator—it takes a fundamentally different approach.
Version 2.41.0 (October 2025) with rodauth-rails 2.1.1 provides 46+ authentication features through an explicit plugin system. Nothing is enabled by default. You turn on exactly what you need.
The architecture is different from Devise. It runs as Rack middleware built on Roda and Sequel, handling auth requests before they hit your Rails router. But here’s the thing—even though it uses Sequel internally, the sequel-activerecord_connection gem lets Sequel reuse your ActiveRecord database connection. No extra connection pool to manage.
The standout security feature is database-level password hash protection. On PostgreSQL, MySQL, and SQL Server, password hashes live in a separate table accessible only via database functions using separate database accounts. Even with SQL injection, attackers can’t directly read password hashes—they’d need to escalate privileges on the database itself. No other Ruby auth framework does this.
The feature list is genuinely impressive:
- Native WebAuthn/passkeys with autofill UI and built-in JavaScript
- TOTP and SMS-based MFA
- Recovery codes
- Magic link authentication
- Password complexity requirements (including common password checking)
- Password expiration and reuse prevention
- Session expiration by inactivity AND maximum lifetime
- Single-session enforcement
- Audit logging
- JSON/JWT API support for everything
The rodauth-oauth extension is OpenID Foundation-certified for OAuth 2.0/OIDC provider capabilities. That’s not something you can bolt onto Devise easily.
Adoption is growing—336,415 downloads since 2020, five releases in 2025 alone. The repo has a 100% issue closure rate (74 issues total, all closed). Ubicloud uses it in production.
The barriers to adoption are real though:
- Steeper learning curve — DSL-based configuration feels foreign if you’re used to model-centric Devise patterns
- Smaller community — fewer Stack Overflow answers when you get stuck
- Rails developers have to adjust — it’s not ActiveRecord-centric
Feature Comparison (The Practical Stuff)
Here’s what you actually get with each option:
| Feature | Rails 8 Generator | Devise | Rodauth |
|---|---|---|---|
| Email/Password Login | ✅ Native | ✅ Native | ✅ Native |
| User Registration | ❌ Build it yourself | ✅ Native | ✅ Native |
| Password Reset | ✅ Native | ✅ Native | ✅ Native |
| Email Confirmation | ❌ Build it yourself | ✅ Module | ✅ Feature |
| Account Lockout | ❌ Build it yourself | ✅ Module | ✅ Feature |
| TOTP MFA | ❌ Build it yourself | ⚠️ devise-two-factor | ✅ Native |
| WebAuthn/Passkeys | ❌ Build it yourself | ⚠️ devise-passkeys | ✅ Native |
| SMS MFA | ❌ Build it yourself | ⚠️ Extension | ✅ Native |
| OAuth Client (Social Login) | ⚠️ OmniAuth | ✅ omniauthable | ⚠️ OmniAuth |
| OAuth Provider | ❌ N/A | ⚠️ Doorkeeper | ✅ rodauth-oauth |
| JWT/JSON API | ❌ Build it yourself | ⚠️ devise-jwt | ✅ Native |
| Session Management | ✅ Database-backed | ⚠️ Cookie-only default | ✅ Advanced |
| Password Policies | ❌ Build it yourself | ❌ Build it yourself | ✅ Native |
A few notes on specific features:
OAuth/social login still means OmniAuth for most people. Rails 8’s generator integrates fine via start_new_session_for after the OAuth callback. Devise’s omniauthable module is the smoothest path. Rodauth works with OmniAuth but shines when you need to be an OAuth provider.
Passkeys are most mature in Rodauth with native features including autofill UI. There’s a new webauthn-rails gem (October 2025) for Rails 8 apps. Devise users need devise-passkeys with custom controller work.
API auth varies significantly. Rodauth has native JSON/JWT for everything with proper access/refresh token flows. Rails 8’s generator gives you sessions—JWT requires manual implementation. Devise users typically reach for devise-jwt or devise_token_auth.
So Which One Should You Actually Use?
Rails 8’s generator makes sense when:
- You’re starting a new project with straightforward auth needs
- You want to actually understand your auth code
- Your registration flow is non-standard (multi-step onboarding, KYC, etc.)
- You’re tired of debugging Devise upgrade issues
- You’re building a Turbo Native/hybrid app where Devise creates friction
Start with the generator, extend as you go. It’s a foundation, not a finished product.
Devise still makes sense when:
- You need confirmable, lockable, timeoutable, trackable, omniauthable working today
- Your team already knows Devise conventions
- You need separate auth for multiple models (User vs Admin)
- Time-to-ship matters more than dependency minimization
- The ecosystem has exactly the extension you need
For enterprise apps with complex security requirements, Devise’s maturity is a feature.
Rodauth makes sense when:
- You need native MFA (TOTP, WebAuthn, SMS) without bolting on gems
- Passwordless authentication is a requirement
- You’re building an OAuth/OIDC provider
- Database-level password hash protection matters to your security team
- You’re building API-first with proper token flows
- Enterprise features like password policies and audit logging are requirements
The learning curve is real, but the capability set is unmatched.
Worth mentioning: Authentication Zero (lazaronixon/authentication-zero) sits between Rails 8’s generator and Devise. It’s a generator that gives you code ownership but includes 2FA with recovery codes, account locking, invitation systems, and activity logs. Good middle ground if the Rails 8 generator feels too minimal but you want to own the code.
If You’re Rolling Your Own
The Stack Overflow wisdom that custom auth is dangerous is worth questioning now. Rails 8’s generator proves the primitives are solid:
has_secure_password— BCrypt hashinghas_secure_token— secure token generationauthenticate_by— timing-attack-resistant credential lookupgenerates_token_for— signed expiring tokens for password resets- Built-in rate limiting
Add the pwned gem for breach database checking and you’ve got a reasonable foundation.
What you need to handle carefully:
- Regenerate session IDs after login (prevents fixation attacks)
- Implement session expiration—both inactivity timeout and maximum lifetime
- Set HttpOnly and Secure flags on cookies
- Never reveal whether an account exists in password reset flows
- Stay on top of Rails security announcements—updates won’t arrive automatically
Migrating from Devise
If you’re considering moving an existing Devise app to Rails 8’s auth, the path is clearer than you might expect.
Session migration that preserves user logins is doable—you can read Devise’s Warden session data. Password columns use compatible BCrypt hashes, so it’s mostly column renaming. Several devs have reported 2-6 hour migration times for moderately complex apps.
Whether it’s worth it depends on the specific pain Devise is causing you. If bundle updates make you nervous, if you’re fighting Devise conventions more than using them, if you want to understand exactly what your auth is doing—migration might be worth the afternoon.
If Devise is working fine and you’re not hitting its limitations, there’s no urgent reason to change. “If it ain’t broke” is legitimate engineering wisdom.
The short version: Rails auth in 2025 has real options. The automatic “just use Devise” answer isn’t wrong, but it’s no longer the only answer. Pick based on what you actually need, not what the community defaulted to in 2010.
Sources & Further Reading
Rails 8 Authentication Generator
- Original PR: Add basic sessions generator by DHH
- GitHub Issue: Add basic authentication generator
- Rails 8 Authentication with the auth generator - Avo
- Rails 8 introduces a basic authentication generator - BigBinary
- New Rails 8 Auth: Choose Your Ideal Setup Guide - Reinteractive
- Built-in Authentication in Rails 8.0 – A Technical Deep Dive
- Rails 8 Authentication Generator With User Registration
- Rails v8 new authentication generator – Money Forward
Devise
- Devise GitHub Repository
- Devise on RubyGems
- Migrating from Devise to Rails Auth
- Replacing Devise with Rails has_secure_password
Rodauth
- Rodauth Documentation
- rodauth-rails GitHub Repository
- Passkey Authentication with Rodauth
- Build an OIDC provider with rodauth-oauth
General Rails Security & Auth