authentication-flow

Rails 8 Authentication

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "authentication-flow" with this command: npx skills add thibautbaissac/rails_ai_agents/thibautbaissac-rails-ai-agents-authentication-flow

Rails 8 Authentication

Overview

Rails 8 includes a built-in authentication generator that creates a complete, secure authentication system without external gems.

Quick Start

Generate authentication

bin/rails generate authentication

Run migrations

bin/rails db:migrate

This creates:

  • User model with has_secure_password

  • Session model for secure sessions

  • Current model for request-local storage

  • Authentication concern for controllers

  • Session and Password controllers

  • Login/logout views

Generated Structure

app/ ├── models/ │ ├── user.rb # User with has_secure_password │ ├── session.rb # Session tracking │ └── current.rb # Current.user accessor ├── controllers/ │ ├── sessions_controller.rb # Login/logout │ ├── passwords_controller.rb # Password reset │ └── concerns/ │ └── authentication.rb # Auth helpers └── views/ ├── sessions/ │ └── new.html.erb # Login form └── passwords/ ├── new.html.erb # Forgot password └── edit.html.erb # Reset password

Core Components

User Model

app/models/user.rb

class User < ApplicationRecord has_secure_password has_many :sessions, dependent: :destroy

normalizes :email_address, with: -> { _1.strip.downcase }

validates :email_address, presence: true, uniqueness: true, format: { with: URI::MailTo::EMAIL_REGEXP } end

Session Model

app/models/session.rb

class Session < ApplicationRecord belongs_to :user

before_create { self.token = SecureRandom.urlsafe_base64(32) }

def self.find_by_token(token) find_by(token: token) if token.present? end end

Current Model

app/models/current.rb

class Current < ActiveSupport::CurrentAttributes attribute :session delegate :user, to: :session, allow_nil: true end

Authentication Concern

app/controllers/concerns/authentication.rb

module Authentication extend ActiveSupport::Concern

included do before_action :require_authentication helper_method :authenticated? end

class_methods do def allow_unauthenticated_access(**options) skip_before_action :require_authentication, **options end end

private

def authenticated? Current.session.present? end

def require_authentication resume_session || request_authentication end

def resume_session if session_token = cookies.signed[:session_token] if session = Session.find_by_token(session_token) Current.session = session end end end

def request_authentication redirect_to new_session_path end

def start_new_session_for(user) session = user.sessions.create! cookies.signed.permanent[:session_token] = { value: session.token, httponly: true } Current.session = session end

def terminate_session Current.session&.destroy cookies.delete(:session_token) end end

Usage Patterns

Protecting Controllers

class ApplicationController < ActionController::Base include Authentication

All actions require authentication by default

end

class PostsController < ApplicationController

All actions protected

end

class HomeController < ApplicationController

Allow public access to specific actions

allow_unauthenticated_access only: [:index, :about] end

Accessing Current User

In controllers

Current.user Current.user.email_address

In views

<%= Current.user.email_address %>

In models (use sparingly)

Current.user

Login Flow

app/controllers/sessions_controller.rb

class SessionsController < ApplicationController allow_unauthenticated_access only: [:new, :create]

def new end

def create if user = User.authenticate_by(email_address: params[:email_address], password: params[:password]) start_new_session_for(user) redirect_to root_path, notice: "Signed in successfully" else flash.now[:alert] = "Invalid email or password" render :new, status: :unprocessable_entity end end

def destroy terminate_session redirect_to root_path, notice: "Signed out" end end

Testing Authentication

Request Specs

spec/requests/sessions_spec.rb

RSpec.describe "Sessions", type: :request do let(:user) { create(:user, password: "password123") }

describe "POST /session" do context "with valid credentials" do it "signs in the user" do post session_path, params: { email_address: user.email_address, password: "password123" }

    expect(response).to redirect_to(root_path)
    expect(cookies[:session_token]).to be_present
  end
end

context "with invalid credentials" do
  it "shows error" do
    post session_path, params: {
      email_address: user.email_address,
      password: "wrong"
    }

    expect(response).to have_http_status(:unprocessable_entity)
  end
end

end

describe "DELETE /session" do it "signs out the user" do # First sign in post session_path, params: { email_address: user.email_address, password: "password123" }

  delete session_path

  expect(response).to redirect_to(root_path)
end

end end

Test Helper

spec/support/authentication_helpers.rb

module AuthenticationHelpers def sign_in(user) session = user.sessions.create! cookies[:session_token] = session.token end

def sign_out cookies.delete(:session_token) end end

RSpec.configure do |config| config.include AuthenticationHelpers, type: :request config.include AuthenticationHelpers, type: :system end

Protected Route Specs

spec/requests/posts_spec.rb

RSpec.describe "Posts", type: :request do let(:user) { create(:user) }

describe "GET /posts" do context "when not authenticated" do it "redirects to login" do get posts_path expect(response).to redirect_to(new_session_path) end end

context "when authenticated" do
  before { sign_in(user) }

  it "shows posts" do
    get posts_path
    expect(response).to have_http_status(:ok)
  end
end

end end

References

  • See sessions.md for session management details

  • See current.md for Current attributes patterns

Common Customizations

Remember Me

def start_new_session_for(user, remember: false) session = user.sessions.create! cookie_options = { value: session.token, httponly: true } cookie_options[:expires] = 2.weeks.from_now if remember cookies.signed.permanent[:session_token] = cookie_options Current.session = session end

Multiple Sessions Tracking

In User model

def active_sessions sessions.where('created_at > ?', 30.days.ago) end

def terminate_all_sessions_except(current_session) sessions.where.not(id: current_session.id).destroy_all end

Rate Limiting

app/controllers/sessions_controller.rb

rate_limit to: 10, within: 3.minutes, only: :create, with: -> { redirect_to new_session_path, alert: "Too many attempts" }

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Automation

hotwire-patterns

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

i18n-patterns

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

rails-controller

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

solid-queue-setup

No summary provided by upstream source.

Repository SourceNeeds Review