Implements authentication using Rails 8 built-in generator. Use when setting up user authentication, login/logout, session management, password reset flows, or securing controllers.
87
88%
Does it follow best practices?
Impact
84%
1.21xAverage score across 3 eval scenarios
Passed
No findings from the security scan
Rails 8 includes a built-in authentication generator that creates a complete, secure authentication system without external gems.
# Generate authentication
bin/rails generate authentication
# Run migrations
bin/rails db:migrateThis creates:
User model with has_secure_passwordSession model for secure sessionsCurrent model for request-local storageapp/
├── 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# 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# 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# app/models/current.rb
class Current < ActiveSupport::CurrentAttributes
attribute :session
delegate :user, to: :session, allow_nil: true
end# 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
endclass 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# In controllers
Current.user
Current.user.email_address
# In views
<%= Current.user.email_address %>
# In models (use sparingly)
Current.user# 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# 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# 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# 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
enddef 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# 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# app/controllers/sessions_controller.rb
rate_limit to: 10, within: 3.minutes, only: :create,
with: -> { redirect_to new_session_path, alert: "Too many attempts" }fernandezbaptiste/rails_ai_agents
15fdeaf
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.