If you’ve tried the new rails generate authentication command in Rails 8, you know it’s a breath of fresh air. It gives you a solid, secure foundation for sessions and login without the "black box" magic of Devise.
However, the generator is intentionally minimal. It gives you the "Login" and "Logout" logic, but it leaves two big holes: How do users sign up? and How do they reset their password?
Because the auth code now lives in your app/ folder, adding these features is straightforward. You don't have to learn a gem's DSL; you just write standard Rails code. Here is how to complete your authentication system in two phases.
Phase 1: The Signup Flow (Registrations)
Signing up a user is just a standard "Create" action in ActiveRecord. We just need a controller and a view.
STEP 1: The Controller
Generate a registrations controller:
rails generate controller registrations
Update the code to create a user and immediately log them in by starting a session:
# app/controllers/registrations_controller.rb
class RegistrationsController < ApplicationController
# Allow guests to see this page!
allow_unauthenticated_access only: %i[ new create ]
def new
@user = User.new
end
def create
@user = User.new(user_params)
if @user.save
# The 'start_new_session_for' method comes from the
# Authenticated concern generated by Rails 8
start_new_session_for @user
redirect_to root_path, notice: "Welcome! You have signed up successfully."
else
render :new, status: :unprocessable_entity
end
end
private
def user_params
params.require(:user).permit(:email_address, :password, :password_confirmation)
end
end
STEP 2: The Routes and View
Add the routes to your config/routes.rb:
get "signup", to: "registrations#new"
post "signup", to: "registrations#create"
In your view (app/views/registrations/new.html.erb), use a standard form. Remember to use email_address as the field name, as that is what the Rails 8 generator uses by default in the User model.
Phase 2: Password Resets (The Modern Way)
In the old days, we had to add a reset_password_token column to our database. In Rails 8, we can use the built-in Generates Token API to create time-sensitive tokens without extra database columns.
STEP 1: Update the User Model
Tell Rails that the User model can generate tokens for password resets.
# app/models/user.rb
class User < ApplicationRecord
has_secure_password
has_many :sessions, dependent: :destroy
# Generate a token that expires in 15 minutes
generates_token_for :password_reset, expires_in: 15.minutes do
password_salt.last(10)
end
end
STEP 2: The Passwords Controller
We need two main actions: create (to send the email) and update (to change the password).
rails generate controller passwords
# app/controllers/passwords_controller.rb
class PasswordsController < ApplicationController
allow_unauthenticated_access
before_action :set_user_by_token, only: %i[ edit update ]
def create
if user = User.find_by(email_address: params[:email_address])
# Send the email (We'll make the mailer in the next step)
PasswordsMailer.reset(user).deliver_later
end
# Always redirect to the same page so hackers can't "fish" for emails
redirect_to new_session_path, notice: "If that email exists, a reset link has been sent."
end
def update
if @user.update(params.permit(:password, :password_confirmation))
redirect_to new_session_path, notice: "Password has been reset. Please log in."
else
render :edit, status: :unprocessable_entity
end
end
private
def set_user_by_token
# Find the user using the token from the URL
@user = User.find_by_token_for!(:password_reset, params[:token])
rescue StandardError
redirect_to new_password_path, alert: "Invalid or expired token."
end
end
STEP 3: The Mailer
Generate a mailer to send the reset link:
rails generate mailer Passwords
# app/mailers/passwords_mailer.rb
class PasswordsMailer < ApplicationMailer
def reset(user)
@user = user
# Generate the token specifically for this email
@token = user.generate_token_for(:password_reset)
mail to: user.email_address, subject: "Reset your password"
end
end
In your mailer view, create the link:
<%= link_to "Reset Password", edit_password_url(token: @token) %>
STEP 4: The Routes
resources :passwords, param: :token
Why this is better than a Gem
- No Hidden Logic: If your "Password Reset" email isn't sending, you can debug it in your own mailer file. You don't have to guess what a gem is doing.
- Speed: You aren't loading extra middleware or heavy dependencies.
- Customization: Want to add an "SMS Reset" later? Or a "Security Question"? You own the controller, so you just add the code.
Summary
The Rails 8 authentication generator is a "starter kit," not a finished product. By adding a RegistrationsController and using the generates_token_for API, you get a full-featured, enterprise-grade auth system that is 100% under your control.
Stop fighting the gems. Start writing the Ruby code.
Top comments (0)