Class: McpAuthenticator

Inherits:
Object
  • Object
show all
Defined in:
app/mcp/mcp_authenticator.rb

Overview

Handles authentication for MCP (Model Context Protocol) requests.
Supports two authentication methods:

  1. Doorkeeper OAuth tokens (preferred for Claude Desktop/native clients)
    Obtained via the OAuth 2.1 authorization code flow with PKCE.
    Service access is scoped by the OAuth application's permitted_services.
    If permitted_services is empty, grants access to all services.

  2. ApiAuthentication bearer tokens (for Cursor/programmatic access)
    Manual tokens created in CRM with per-token service scoping.

Security Requirements:

  1. Request must come from the MCP subdomain (mcp.warmlyyours.com)
  2. Client must send Bearer token in Authorization header
  3. Token must be valid and not expired/revoked
  4. Account must be an employee with 'mcp_access' role (admin has it by default)

Returns an AuthResult (or OAuthAuthResult) containing the account and auth info.

Defined Under Namespace

Classes: AuthResult, AuthenticationError, AuthorizationError, OAuthAuthResult

Constant Summary collapse

REQUIRED_ROLE =
'mcp_access'
ALLOWED_SUBDOMAINS =
%w[mcp].freeze
ENV_KEY =

Rack env key for storing auth result

'mcp.auth_result'

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(request) ⇒ McpAuthenticator

Returns a new instance of McpAuthenticator.



101
102
103
# File 'app/mcp/mcp_authenticator.rb', line 101

def initialize(request)
  @request = request
end

Class Method Details

.authenticate(request) ⇒ AuthResult, ...

Check if a request is authenticated (doesn't raise)

Parameters:

  • request (Rack::Request)

    The incoming request

Returns:



97
98
99
# File 'app/mcp/mcp_authenticator.rb', line 97

def self.authenticate(request)
  new(request).authenticate
end

.authenticate!(request) ⇒ AuthResult, OAuthAuthResult

Authenticate a request and return an AuthResult

Parameters:

  • request (Rack::Request)

    The incoming request

Returns:

Raises:



90
91
92
# File 'app/mcp/mcp_authenticator.rb', line 90

def self.authenticate!(request)
  new(request).authenticate!
end

Instance Method Details

#authenticateObject



112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'app/mcp/mcp_authenticator.rb', line 112

def authenticate
  # Verify request is from allowed subdomain
  return nil unless valid_subdomain?

  token_string = extract_bearer_token
  return nil if token_string.blank?

  # Try Doorkeeper OAuth token first
  result = authenticate_doorkeeper(token_string)
  return result if result

  # Fall back to ApiAuthentication bearer token
  authenticate_api_token(token_string)
end

#authenticate!Object



105
106
107
108
109
110
# File 'app/mcp/mcp_authenticator.rb', line 105

def authenticate!
  result = authenticate
  raise AuthenticationError, 'Invalid or missing authentication token' unless result

  result
end