Class: ActionMCP::GatewayIdentifier

Inherits:
Object
  • Object
show all
Defined in:
lib/action_mcp/gateway_identifier.rb

Overview

Base class for Gateway authentication identifiers.

Gateway identifiers provide a clean interface for authentication by reading from request.env keys set by upstream middleware (like Warden, Devise, or custom auth).

Examples:

Warden/Devise Integration

class WardenIdentifier < ActionMCP::GatewayIdentifier
  identifier :user
  authenticates :warden

  def resolve
    # Warden sets 'warden.user' in request.env after authentication
    user = user_from_middleware
    user || raise(Unauthorized, "No authenticated user found")
  end
end

API Key Authentication

class ApiKeyIdentifier < ActionMCP::GatewayIdentifier
  identifier :user
  authenticates :api_key

  def resolve
    # Check for API key in header or query param
    api_key = @request.env['HTTP_X_API_KEY'] ||
              @request.params['api_key']
    return raise(Unauthorized, "Missing API key") unless api_key

    user = User.find_by(api_key: api_key)
    user || raise(Unauthorized, "Invalid API key")
  end
end

Session-based Authentication

class SessionIdentifier < ActionMCP::GatewayIdentifier
  identifier :user
  authenticates :session

  def resolve
    user_id = session&.[]('user_id')
    return raise(Unauthorized, "No user session") unless user_id

    user = User.find_by(id: user_id)
    user || raise(Unauthorized, "Invalid session")
  end
end

Multi-tenant with Organization

class TenantIdentifier < ActionMCP::GatewayIdentifier
  identifier :user
  authenticates :tenant

  def resolve
    # Get user from middleware
    user = user_from_middleware
    return raise(Unauthorized, "No user found") unless user

    # Check tenant header
    tenant_id = @request.env['HTTP_X_TENANT_ID']
    return raise(Unauthorized, "Missing tenant") unless tenant_id

    # Verify user has access to tenant
    unless user.tenants.exists?(id: tenant_id)
      raise Unauthorized, "Access denied for tenant"
    end

    # Set current tenant for the request
    Current.tenant = Tenant.find(tenant_id)
    user
  end
end

Development/Testing Bypass

class DevIdentifier < ActionMCP::GatewayIdentifier
  identifier :user
  authenticates :dev

  def resolve
    return raise(Unauthorized, "Dev auth disabled in production") unless development_env?

    # Create or find dev user
    User.find_or_create_by!(email: "dev@localhost") do |user|
      user.name = "Development User"
    end
  end
end

Defined Under Namespace

Classes: Unauthorized

Class Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(request) ⇒ GatewayIdentifier

Returns a new instance of GatewayIdentifier.

Parameters:

  • request (ActionDispatch::Request)

    The request object containing env hash



124
125
126
# File 'lib/action_mcp/gateway_identifier.rb', line 124

def initialize(request)
  @request = request
end

Class Attribute Details

.auth_methodString (readonly)

Returns The authentication method this identifier handles (e.g., “session”, “api_key”).

Returns:

  • (String)

    The authentication method this identifier handles (e.g., “session”, “api_key”)



98
99
100
# File 'lib/action_mcp/gateway_identifier.rb', line 98

def auth_method
  @auth_method
end

.identifier_nameSymbol (readonly)

Returns The name of the identity this identifier provides (e.g., :user, :admin).

Returns:

  • (Symbol)

    The name of the identity this identifier provides (e.g., :user, :admin)



95
96
97
# File 'lib/action_mcp/gateway_identifier.rb', line 95

def identifier_name
  @identifier_name
end

Class Method Details

.authenticates(method) ⇒ Object

Declares what authentication method this identifier handles. This should match values in your authentication_methods configuration.

Examples:

authenticates :api_key
# Matches authentication_methods: ["api_key"] in config

Parameters:

  • method (Symbol, String)

    The auth method name (e.g., :session, :api_key)



118
119
120
# File 'lib/action_mcp/gateway_identifier.rb', line 118

def authenticates(method)
  @auth_method = method.to_s
end

.identifier(name) ⇒ Object

Declares what identity attribute this identifier provides. This becomes the accessor name on the Gateway instance.

Examples:

identifier :user
# Gateway instance will have gateway.user accessor

Parameters:

  • name (Symbol, String)

    The identity name (e.g., :user, :admin)



107
108
109
# File 'lib/action_mcp/gateway_identifier.rb', line 107

def identifier(name)
  @identifier_name = name.to_sym
end

Instance Method Details

#resolveObject

This method is abstract.

Subclasses must implement this method

Resolves the identity for this authentication method. Must return a truthy identity object, or raise Unauthorized.

Common request.env keys set by popular auth middleware:

  • ‘warden.user’ - Warden (used by Devise)

  • ‘devise.user’ - Devise direct

  • ‘rack.session’ - Rack session hash

  • ‘HTTP_AUTHORIZATION’ - Authorization header

  • Custom keys set by your middleware

Returns:

  • (Object)

    The authenticated identity (User, Admin, etc.)

Raises:



141
142
143
# File 'lib/action_mcp/gateway_identifier.rb', line 141

def resolve
  raise NotImplementedError, "#{self.class}#resolve must be implemented"
end