CrackedRuby CrackedRuby

Authentication vs Authorization

Overview

Authentication and authorization represent two distinct security mechanisms that control access to application resources. Authentication verifies identity—confirming that users are who they claim to be. Authorization determines permissions—defining what authenticated users can access or modify within the system.

The distinction matters because these processes serve different security functions and occur at different stages of access control. Authentication happens first, establishing user identity through credentials like passwords, tokens, or biometric data. Authorization follows, checking the authenticated identity against access rules to grant or deny specific operations.

Consider a web application: when users enter their username and password, the system performs authentication by validating credentials against stored records. After successful authentication, when users attempt to view another user's profile or delete a post, the system performs authorization by checking whether their role permits those actions.

This separation of concerns enables flexible security models. Systems can authenticate users through multiple methods while maintaining centralized authorization logic. Applications can also implement different authorization schemes for the same authenticated users based on context, resource sensitivity, or business rules.

Key Principles

Authentication establishes identity through credential verification. The process involves presenting credentials (knowledge factors like passwords, possession factors like security keys, or inherence factors like fingerprints) and validating them against stored authentication data. Successful authentication produces an identity token or session that represents the authenticated user for subsequent requests.

Authentication mechanisms vary in strength and implementation complexity. Password-based authentication compares submitted passwords against stored hashes. Token-based authentication validates cryptographic tokens issued during initial login. Multi-factor authentication combines multiple credential types to increase security. Certificate-based authentication verifies cryptographic certificates issued by trusted authorities.

The authentication process typically generates a session identifier or authentication token after successful verification. This token accompanies subsequent requests, allowing the system to recognize the authenticated user without requiring credential resubmission for each action. Session tokens expire after defined periods to limit exposure from token theft.

Authorization operates on the established identity to control resource access. The system evaluates whether the authenticated identity has permission to perform requested operations on specific resources. Authorization decisions consider multiple factors: user roles, resource ownership, operation type, and contextual conditions like time of day or IP address.

Authorization models structure permission decisions differently. Role-Based Access Control (RBAC) assigns permissions to roles, then assigns roles to users. Users inherit permissions from all assigned roles. Attribute-Based Access Control (ABAC) evaluates attributes of users, resources, and environmental context to make decisions. Access Control Lists (ACL) attach permissions directly to resources, specifying which users or groups can perform which operations.

The authorization process occurs after authentication establishes identity. Each request carries authentication credentials or tokens that identify the user. The authorization system loads the user's permissions, evaluates them against the requested operation and resource, then allows or denies the request. This evaluation happens for every access attempt, even when users remain authenticated for extended periods.

Separation between authentication and authorization enables independent evolution of each mechanism. Applications can change authentication methods—from passwords to OAuth to biometrics—without modifying authorization logic. Organizations can restructure permission models without affecting how users authenticate. This decoupling reduces complexity and improves security by allowing each system to focus on its specific responsibility.

Security Implications

Authentication vulnerabilities expose systems to identity theft and unauthorized access. Weak password policies allow brute force attacks to guess credentials. Credential storage flaws, like plain text passwords or weak hashing algorithms, enable attackers who breach databases to immediately access accounts. Session token weaknesses permit session hijacking, where attackers steal tokens to impersonate authenticated users.

Secure authentication requires strong credential storage. Systems must hash passwords using algorithms like bcrypt, scrypt, or Argon2 that resist brute force attacks through computational cost. Password hashing should include per-user salts to prevent rainbow table attacks. Never store passwords reversibly or use fast hashing functions like MD5 or SHA-1 for credential storage.

require 'bcrypt'

# Secure password storage
class User
  attr_accessor :email, :password_hash
  
  def password=(new_password)
    @password_hash = BCrypt::Password.create(new_password)
  end
  
  def authenticate(password_attempt)
    BCrypt::Password.new(@password_hash) == password_attempt
  end
end

user = User.new
user.email = "user@example.com"
user.password = "secure_password_123"
# => Stores hashed password

user.authenticate("wrong_password")
# => false

user.authenticate("secure_password_123")
# => true

Session token security prevents unauthorized access after authentication. Tokens should be cryptographically random with sufficient entropy to resist guessing. Applications must implement token expiration, forcing reauthentication after defined periods. Secure cookies require HttpOnly flags to prevent JavaScript access and Secure flags to ensure HTTPS-only transmission. Token rotation on privilege escalation limits exposure from stolen tokens.

Multi-factor authentication significantly improves security by requiring multiple credential types. Even if attackers steal passwords, they cannot authenticate without the second factor. Time-based One-Time Passwords (TOTP) generate temporary codes from shared secrets. SMS-based codes send authentication values to registered phone numbers. Hardware tokens provide possession-based authentication that resists remote attacks.

Authorization vulnerabilities allow privilege escalation where users access resources beyond their permissions. Insecure Direct Object References (IDOR) occur when applications fail to verify authorization before serving requested resources. Parameter tampering enables users to modify request parameters to access unauthorized data. Missing function-level access control allows users to invoke administrative functions by directly calling endpoints.

Secure authorization requires explicit permission checks for every access attempt. Applications must verify authorization after authentication but before serving resources or executing operations. Permission checks should occur at multiple levels: controller actions must verify broad access rights, while service layer logic enforces resource-specific permissions based on ownership and roles.

class PostsController < ApplicationController
  before_action :authenticate_user!
  before_action :set_post, only: [:show, :edit, :update, :destroy]
  before_action :authorize_post_access, only: [:edit, :update, :destroy]
  
  def show
    # Public posts visible to all authenticated users
    # Authorization check happens in set_post
  end
  
  def edit
    # Only authorized users reach this action
  end
  
  def update
    if @post.update(post_params)
      redirect_to @post
    else
      render :edit
    end
  end
  
  private
  
  def set_post
    @post = Post.find(params[:id])
    # Verify basic read access
    authorize_read_access
  end
  
  def authorize_read_access
    unless @post.public? || @post.user == current_user || current_user.admin?
      redirect_to root_path, alert: "Not authorized"
    end
  end
  
  def authorize_post_access
    unless @post.user == current_user || current_user.admin?
      redirect_to root_path, alert: "Not authorized"
    end
  end
end

Horizontal privilege escalation occurs when users access resources belonging to other users at the same privilege level. Applications must verify resource ownership or explicit permissions before allowing access. Database queries should filter results by user identity, not rely solely on client-provided identifiers. Parameter validation must reject attempts to access resources through ID manipulation.

Vertical privilege escalation enables regular users to perform administrative functions. Applications must implement role checks for sensitive operations, not just authentication checks. Administrative endpoints require explicit role verification. Default deny policies improve security by requiring explicit permission grants rather than blocking known unauthorized operations.

Time-of-check to time-of-use (TOCTOU) vulnerabilities arise when authorization checks occur separately from resource access. Attackers can modify state between the authorization check and actual operation. Applications should perform authorization checks atomically with resource operations, or implement locking mechanisms to prevent state changes between check and use.

Ruby Implementation

Ruby applications implement authentication through various gems and frameworks. Devise provides comprehensive authentication including password resets, email confirmation, and session management. Clearance offers simpler authentication for applications needing basic functionality. Authlogic gives developers more control through explicit authentication logic rather than framework magic.

Devise integrates authentication into Rails applications through generated models, controllers, and views. The gem handles password encryption, session management, and security features like Rememberable for persistent sessions and Lockable for account locking after failed attempts.

# Gemfile
gem 'devise'

# app/models/user.rb
class User < ApplicationRecord
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable,
         :confirmable, :lockable, :timeoutable
end

# config/routes.rb
Rails.application.routes.draw do
  devise_for :users
end

# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  before_action :authenticate_user!
  
  def current_user
    # Provided by Devise
  end
end

JWT authentication supports stateless authentication for API applications. The server signs tokens containing user identity and expiration data. Clients include tokens in request headers for authentication. The server verifies signatures and expiration before authorizing requests.

require 'jwt'

class AuthenticationService
  SECRET_KEY = ENV['JWT_SECRET_KEY']
  ALGORITHM = 'HS256'
  
  def self.encode_token(payload, expiration = 24.hours.from_now)
    payload[:exp] = expiration.to_i
    JWT.encode(payload, SECRET_KEY, ALGORITHM)
  end
  
  def self.decode_token(token)
    decoded = JWT.decode(token, SECRET_KEY, true, algorithm: ALGORITHM)
    decoded[0]
  rescue JWT::DecodeError, JWT::ExpiredSignature
    nil
  end
end

# Usage in controller
class ApiController < ActionController::API
  before_action :authenticate_request
  
  private
  
  def authenticate_request
    header = request.headers['Authorization']
    token = header.split(' ').last if header
    decoded = AuthenticationService.decode_token(token)
    
    if decoded
      @current_user = User.find(decoded['user_id'])
    else
      render json: { error: 'Unauthorized' }, status: :unauthorized
    end
  end
end

Authorization in Ruby applications uses specialized gems for permission management. Pundit implements policy-based authorization where each model has a corresponding policy class defining permissions. CanCanCan uses ability classes to centralize authorization rules. ActionPolicy provides behavior-driven authorization with explicit policy testing.

Pundit structures authorization around policy classes that define permission methods. Controllers query policies before allowing actions. Policies receive the current user and resource, returning boolean values indicating permission status.

# Gemfile
gem 'pundit'

# app/policies/post_policy.rb
class PostPolicy
  attr_reader :user, :post
  
  def initialize(user, post)
    @user = user
    @post = post
  end
  
  def show?
    post.published? || post.user == user || user.admin?
  end
  
  def update?
    post.user == user || user.admin?
  end
  
  def destroy?
    post.user == user || user.admin?
  end
  
  class Scope
    attr_reader :user, :scope
    
    def initialize(user, scope)
      @user = user
      @scope = scope
    end
    
    def resolve
      if user.admin?
        scope.all
      else
        scope.where(published: true).or(scope.where(user: user))
      end
    end
  end
end

# app/controllers/posts_controller.rb
class PostsController < ApplicationController
  include Pundit::Authorization
  
  def index
    @posts = policy_scope(Post)
  end
  
  def show
    @post = Post.find(params[:id])
    authorize @post
  end
  
  def update
    @post = Post.find(params[:id])
    authorize @post
    
    if @post.update(post_params)
      redirect_to @post
    else
      render :edit
    end
  end
end

CanCanCan centralizes authorization in ability classes that define what users can do. The gem uses a declarative syntax specifying abilities for roles or conditions. Controllers check abilities using simple method calls.

# Gemfile
gem 'cancancan'

# app/models/ability.rb
class Ability
  include CanCan::Ability
  
  def initialize(user)
    user ||= User.new # guest user
    
    if user.admin?
      can :manage, :all
    elsif user.moderator?
      can :read, Post, published: true
      can :manage, Post, user_id: user.id
      can :manage, Comment
    else
      can :read, Post, published: true
      can :create, Post
      can :manage, Post, user_id: user.id
      can :create, Comment
      can :manage, Comment, user_id: user.id
    end
  end
end

# app/controllers/posts_controller.rb
class PostsController < ApplicationController
  load_and_authorize_resource
  
  def show
    # @post already loaded and authorized
  end
  
  def update
    if @post.update(post_params)
      redirect_to @post
    else
      render :edit
    end
  end
end

Custom authorization implementations provide flexibility for complex requirements. Applications can build authorization services that evaluate permissions based on multiple factors including user attributes, resource state, and environmental context.

class AuthorizationService
  def initialize(user)
    @user = user
  end
  
  def can?(action, resource)
    case resource
    when Post
      can_access_post?(action, resource)
    when Comment
      can_access_comment?(action, resource)
    else
      false
    end
  end
  
  private
  
  def can_access_post?(action, post)
    case action
    when :read
      post.published? || post.user == @user || @user.admin?
    when :create
      @user.present?
    when :update, :destroy
      post.user == @user || @user.admin?
    else
      false
    end
  end
  
  def can_access_comment?(action, comment)
    case action
    when :read
      comment.post.published? || @user.admin?
    when :create
      @user.present? && comment.post.published?
    when :update, :destroy
      comment.user == @user || @user.admin?
    else
      false
    end
  end
end

# Usage in controllers
class ApplicationController < ActionController::Base
  def authorize_action(action, resource)
    service = AuthorizationService.new(current_user)
    unless service.can?(action, resource)
      redirect_to root_path, alert: "Not authorized"
    end
  end
end

Practical Examples

Web applications demonstrate the interaction between authentication and authorization. Users authenticate through login forms, receiving session cookies that persist their identity. Subsequent requests use session cookies for authentication, then authorization checks determine whether authenticated users can perform requested actions.

# Authentication: Login action
class SessionsController < ApplicationController
  skip_before_action :authenticate_user!, only: [:new, :create]
  
  def new
    # Login form
  end
  
  def create
    user = User.find_by(email: params[:email])
    
    if user && user.authenticate(params[:password])
      # Authentication successful
      session[:user_id] = user.id
      redirect_to dashboard_path
    else
      # Authentication failed
      flash.now[:alert] = "Invalid email or password"
      render :new
    end
  end
  
  def destroy
    session[:user_id] = nil
    redirect_to root_path
  end
end

# Application controller handles authentication
class ApplicationController < ActionController::Base
  before_action :authenticate_user!
  
  private
  
  def authenticate_user!
    unless current_user
      redirect_to login_path, alert: "Please log in"
    end
  end
  
  def current_user
    @current_user ||= User.find_by(id: session[:user_id])
  end
end

# Authorization: Resource controller
class ArticlesController < ApplicationController
  def edit
    @article = Article.find(params[:id])
    
    # Authorization check
    unless @article.user == current_user || current_user.admin?
      redirect_to articles_path, alert: "Not authorized"
    end
  end
end

API applications implement token-based authentication without server-side sessions. Clients authenticate by submitting credentials to receive JWT tokens. Subsequent API requests include tokens in Authorization headers. The server validates tokens to authenticate requests, then checks permissions to authorize operations.

class AuthController < ApiController
  skip_before_action :authenticate_request, only: [:login]
  
  def login
    user = User.find_by(email: params[:email])
    
    if user && user.authenticate(params[:password])
      token = AuthenticationService.encode_token(
        user_id: user.id,
        email: user.email,
        role: user.role
      )
      render json: { token: token, user: user }, status: :ok
    else
      render json: { error: 'Invalid credentials' }, status: :unauthorized
    end
  end
end

class ArticlesController < ApiController
  def create
    article = Article.new(article_params)
    article.user = @current_user
    
    if article.save
      render json: article, status: :created
    else
      render json: { errors: article.errors }, status: :unprocessable_entity
    end
  end
  
  def update
    article = Article.find(params[:id])
    
    # Authorization check
    unless article.user == @current_user || @current_user.admin?
      return render json: { error: 'Forbidden' }, status: :forbidden
    end
    
    if article.update(article_params)
      render json: article
    else
      render json: { errors: article.errors }, status: :unprocessable_entity
    end
  end
end

Multi-tenant applications separate authentication from tenant-specific authorization. Users authenticate once but may have different permissions across multiple tenants. Authorization checks must verify both user identity and tenant-specific permissions.

class Account < ApplicationRecord
  has_many :memberships
  has_many :users, through: :memberships
  has_many :projects
end

class Membership < ApplicationRecord
  belongs_to :account
  belongs_to :user
  
  enum role: { viewer: 0, editor: 1, admin: 2, owner: 3 }
end

class ApplicationController < ActionController::Base
  before_action :authenticate_user!
  before_action :set_current_account
  
  private
  
  def set_current_account
    @current_account = Account.find_by(subdomain: request.subdomain)
    @current_membership = @current_account.memberships.find_by(user: current_user)
    
    unless @current_membership
      redirect_to accounts_path, alert: "Access denied to this account"
    end
  end
  
  def authorize_account_action(required_role)
    role_levels = { viewer: 0, editor: 1, admin: 2, owner: 3 }
    user_level = role_levels[@current_membership.role.to_sym]
    required_level = role_levels[required_role]
    
    unless user_level >= required_level
      redirect_to account_path(@current_account), 
                  alert: "Insufficient permissions"
    end
  end
end

class ProjectsController < ApplicationController
  def create
    authorize_account_action(:editor)
    
    @project = @current_account.projects.build(project_params)
    @project.user = current_user
    
    if @project.save
      redirect_to @project
    else
      render :new
    end
  end
  
  def destroy
    @project = @current_account.projects.find(params[:id])
    authorize_account_action(:admin)
    
    @project.destroy
    redirect_to projects_path
  end
end

OAuth authentication enables users to authenticate through third-party providers. Applications redirect users to providers for authentication, receiving authorization codes after successful authentication. Applications exchange codes for access tokens, using tokens to retrieve user information and authenticate users in the application.

# config/initializers/omniauth.rb
Rails.application.config.middleware.use OmniAuth::Builder do
  provider :google_oauth2, ENV['GOOGLE_CLIENT_ID'], ENV['GOOGLE_CLIENT_SECRET'],
    {
      scope: 'email,profile',
      prompt: 'select_account'
    }
end

class SessionsController < ApplicationController
  def create_from_omniauth
    auth = request.env['omniauth.auth']
    
    # Find or create user from OAuth data
    user = User.find_or_create_by(provider: auth.provider, uid: auth.uid) do |u|
      u.email = auth.info.email
      u.name = auth.info.name
      u.oauth_token = auth.credentials.token
      u.oauth_expires_at = Time.at(auth.credentials.expires_at)
    end
    
    session[:user_id] = user.id
    redirect_to root_path
  end
end

Common Pitfalls

Confusing authentication with authorization leads to security vulnerabilities. Developers sometimes implement authentication checks but assume authenticated users can access all resources. Applications must explicitly authorize each action, not just verify authentication. Authentication confirms identity while authorization controls access.

# INCORRECT: Only checks authentication
class PostsController < ApplicationController
  before_action :authenticate_user!
  
  def destroy
    @post = Post.find(params[:id])
    @post.destroy
    redirect_to posts_path
  end
end

# CORRECT: Checks both authentication and authorization
class PostsController < ApplicationController
  before_action :authenticate_user!
  
  def destroy
    @post = Post.find(params[:id])
    
    unless @post.user == current_user || current_user.admin?
      redirect_to posts_path, alert: "Not authorized"
      return
    end
    
    @post.destroy
    redirect_to posts_path
  end
end

Relying on client-side authorization creates security holes. JavaScript that hides UI elements does not prevent unauthorized API calls. Users can manipulate browser state or call APIs directly to bypass client-side restrictions. Applications must enforce authorization on the server for every request.

Storing authentication tokens in localStorage exposes applications to XSS attacks. JavaScript running in the page can access localStorage, allowing attackers to steal tokens through injected scripts. Session cookies with HttpOnly flags prevent JavaScript access, improving security. Applications requiring localStorage for tokens must implement strong XSS protections.

Implementing authentication without proper session management creates vulnerabilities. Applications must implement session expiration, forcing reauthentication after inactivity periods. Sessions should invalidate on logout, preventing reuse of old session identifiers. Password changes should invalidate existing sessions, ensuring stolen credentials become useless after password resets.

Missing authorization checks on API endpoints allow unauthorized access. Developers sometimes secure web UI routes but forget to protect API endpoints with equivalent authorization. APIs must implement the same authorization logic as web interfaces. Each endpoint requires explicit authorization validation.

# INCORRECT: Missing authorization on API endpoint
class Api::PostsController < ApiController
  def update
    @post = Post.find(params[:id])
    
    if @post.update(post_params)
      render json: @post
    else
      render json: { errors: @post.errors }, status: :unprocessable_entity
    end
  end
end

# CORRECT: Authorization check before operation
class Api::PostsController < ApiController
  def update
    @post = Post.find(params[:id])
    
    unless @post.user == current_user || current_user.admin?
      return render json: { error: 'Forbidden' }, status: :forbidden
    end
    
    if @post.update(post_params)
      render json: @post
    else
      render json: { errors: @post.errors }, status: :unprocessable_entity
    end
  end
end

Hardcoding role checks throughout the application creates maintenance problems. Authorization logic scattered across controllers becomes difficult to update consistently. Centralizing authorization in policy classes or ability definitions enables consistent enforcement and easier modifications.

Using authentication tokens as authorization tokens conflates identity verification with permission grants. JWT tokens containing user IDs authenticate users but do not inherently authorize actions. Applications must still query user permissions and evaluate them against requested operations. Tokens can include permission data to reduce database queries, but must be validated carefully to prevent tampering.

Failing to validate token expiration enables attackers to use stolen tokens indefinitely. Authentication systems must implement token expiration with reasonable timeouts. Short-lived tokens improve security by limiting exposure windows. Refresh token mechanisms enable extended sessions while maintaining short access token lifetimes.

Implementing authorization without considering resource ownership creates horizontal privilege escalation. Checking user roles without verifying resource ownership allows users to modify other users' data. Authorization logic must verify both role-based permissions and resource-specific ownership or explicit grants.

Design Considerations

Selecting authentication methods balances security requirements against user experience. Password-based authentication provides familiar workflows but depends on users choosing strong passwords. Multi-factor authentication significantly improves security but adds friction to the login process. Biometric authentication offers convenience but requires specialized hardware and raises privacy concerns.

Token-based authentication suits API-driven applications and mobile clients. Tokens enable stateless authentication, eliminating server-side session storage requirements. JWT tokens encode user information and permissions, reducing database queries for each request. However, tokens cannot be revoked before expiration without additional infrastructure like token blacklists or short expiration times with refresh tokens.

OAuth and social login reduce authentication implementation complexity by delegating to established providers. Users benefit from single sign-on across services and avoid creating additional passwords. Applications must trust OAuth providers and handle cases where providers become unavailable or users revoke access. OAuth also introduces dependency on external services for critical authentication functionality.

Authorization model selection depends on application complexity and permission structures. RBAC works well for applications with stable roles and clear organizational hierarchies. Users receive roles that grant collections of permissions. RBAC simplifies permission management when users fit cleanly into defined roles but struggles with fine-grained permissions or dynamic access rules.

ABAC provides flexibility for complex authorization scenarios. Policies evaluate multiple attributes including user properties, resource metadata, and environmental context. ABAC handles dynamic permissions that change based on conditions like time, location, or data sensitivity. However, ABAC policies become complex to author, understand, and debug as rule sets grow.

ACL authorization works well for applications where resources have clear ownership and users need specific permissions on individual resources. File systems and document management systems commonly use ACLs. ACLs allow fine-grained control but become difficult to manage at scale when permission grants multiply across many resources and users.

Implementing authorization at the application layer versus database layer involves trade-offs. Application-layer authorization using frameworks like Pundit or CanCanCan provides flexible, testable permission logic. Applications can implement complex business rules and integrate permissions with application state. However, authorization happens after data retrieval, requiring careful implementation to avoid loading unauthorized data.

Database-layer authorization using row-level security policies enforces permissions at the database level. PostgreSQL row security policies automatically filter query results based on user context. This approach prevents unauthorized data access even when application code contains bugs. Database authorization requires careful policy design and testing to ensure correct behavior across different query patterns.

Distributed systems complicate authentication and authorization. Services must share authentication state or validate tokens independently. Centralized authentication services issue tokens that distributed services validate. This architecture requires secure token distribution and validation across services. Services should validate tokens locally to avoid authentication becoming a bottleneck.

Authorization in distributed systems requires careful consideration of data synchronization. Services need consistent permission information to make correct authorization decisions. Centralized permission services provide consistency but add latency and create single points of failure. Cached permissions improve performance but introduce consistency challenges when permissions change.

Reference

Authentication Methods Comparison

Method Security Level Implementation Complexity User Experience Use Cases
Password Medium Low Familiar General web applications
Multi-Factor High Medium Additional step Sensitive applications
Token-Based Medium-High Medium Seamless for APIs APIs and mobile apps
OAuth/Social Medium Medium Convenient Consumer applications
Certificate High High Transparent Enterprise and IoT
Biometric High High Convenient Mobile applications

Authorization Models Comparison

Model Best For Complexity Flexibility Management Overhead
RBAC Stable organizational roles Low Medium Low
ABAC Dynamic complex rules High High Medium
ACL Resource-specific permissions Medium Medium High at scale
Policy-Based Complex business rules Medium High Medium

Common HTTP Status Codes

Status Code Meaning Usage
200 OK Request successful Successful authentication or authorized access
401 Unauthorized Authentication failed Invalid credentials or missing authentication
403 Forbidden Authorization failed Valid authentication but insufficient permissions
404 Not Found Resource not found Can hide unauthorized resource existence

Ruby Authentication Gems

Gem Approach Flexibility Features
Devise Full-featured framework Medium Password reset, confirmable, lockable
Clearance Lightweight framework Medium Simple authentication workflows
Authlogic Explicit authentication High Developer controls logic flow
Sorcery Modular approach High Pick needed features only
JWT Token-based High Stateless API authentication

Ruby Authorization Gems

Gem Approach Learning Curve Best For
Pundit Policy objects Low Object-oriented permissions
CanCanCan Ability definitions Low Centralized authorization
ActionPolicy Behavior-driven Medium Complex policy testing
Rolify Role management Low RBAC implementations

Security Headers for Authentication

Header Purpose Example
Authorization Carry authentication tokens Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
WWW-Authenticate Indicate authentication required Bearer realm="api"
Set-Cookie Establish session cookies session_id=abc123; HttpOnly; Secure

Session Cookie Flags

Flag Purpose Security Benefit
HttpOnly Prevent JavaScript access Protects against XSS token theft
Secure HTTPS-only transmission Prevents token interception
SameSite Control cross-site requests Mitigates CSRF attacks
Max-Age Session expiration Limits token lifetime exposure

Common Authorization Checks

Check Type Validates Implementation
Role check User has required role user.role == 'admin'
Ownership check User owns resource resource.user_id == user.id
Permission check User has specific permission user.can?(:delete, resource)
Scope check Resource in accessible scope user.accessible_resources.include?(resource)