Class: MCPClient::Auth::OAuthProvider
- Inherits:
-
Object
- Object
- MCPClient::Auth::OAuthProvider
- Defined in:
- lib/mcp_client/auth/oauth_provider.rb
Overview
OAuth 2.1 provider for MCP client authentication Handles the complete OAuth flow including server discovery, client registration, authorization, token exchange, and refresh
Defined Under Namespace
Classes: MemoryStorage
Instance Attribute Summary collapse
-
#logger ⇒ Logger
Logger instance.
-
#redirect_uri ⇒ String
OAuth redirect URI.
-
#scope ⇒ String, ...
OAuth scope (use :all for all server-supported scopes).
-
#server_url ⇒ String
The MCP server URL (normalized).
-
#storage ⇒ Object
Storage backend for tokens and client info.
Instance Method Summary collapse
-
#access_token ⇒ Token?
Get current access token (refresh if needed).
-
#apply_authorization(request) ⇒ void
Apply OAuth authorization to HTTP request.
-
#complete_authorization_flow(code, state) ⇒ Token
Complete OAuth authorization flow with authorization code.
-
#handle_unauthorized_response(response) ⇒ ResourceMetadata?
Handle 401 Unauthorized response (for server discovery).
-
#initialize(server_url:, redirect_uri: 'http://localhost:8080/callback', scope: nil, logger: nil, storage: nil, client_metadata: {}) ⇒ OAuthProvider
constructor
Initialize OAuth provider.
-
#start_authorization_flow ⇒ String
Start OAuth authorization flow.
-
#supported_scopes ⇒ Array<String>
Return the scopes supported by the authorization server Discovers server metadata and returns the scopes_supported list.
Constructor Details
#initialize(server_url:, redirect_uri: 'http://localhost:8080/callback', scope: nil, logger: nil, storage: nil, client_metadata: {}) ⇒ OAuthProvider
Initialize OAuth provider
35 36 37 38 39 40 41 42 43 44 |
# File 'lib/mcp_client/auth/oauth_provider.rb', line 35 def initialize(server_url:, redirect_uri: 'http://localhost:8080/callback', scope: nil, logger: nil, storage: nil, client_metadata: {}) self.server_url = server_url self.redirect_uri = redirect_uri self.scope = scope self.logger = logger || Logger.new($stdout, level: Logger::WARN) self.storage = storage || MemoryStorage.new = @http_client = create_http_client end |
Instance Attribute Details
#logger ⇒ Logger
Returns Logger instance.
24 |
# File 'lib/mcp_client/auth/oauth_provider.rb', line 24 attr_accessor :redirect_uri, :scope, :logger, :storage |
#redirect_uri ⇒ String
Returns OAuth redirect URI.
24 25 26 |
# File 'lib/mcp_client/auth/oauth_provider.rb', line 24 def redirect_uri @redirect_uri end |
#scope ⇒ String, ...
Returns OAuth scope (use :all for all server-supported scopes).
24 |
# File 'lib/mcp_client/auth/oauth_provider.rb', line 24 attr_accessor :redirect_uri, :scope, :logger, :storage |
#server_url ⇒ String
Returns The MCP server URL (normalized).
24 |
# File 'lib/mcp_client/auth/oauth_provider.rb', line 24 attr_accessor :redirect_uri, :scope, :logger, :storage |
#storage ⇒ Object
Returns Storage backend for tokens and client info.
24 |
# File 'lib/mcp_client/auth/oauth_provider.rb', line 24 attr_accessor :redirect_uri, :scope, :logger, :storage |
Instance Method Details
#access_token ⇒ Token?
Get current access token (refresh if needed)
53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/mcp_client/auth/oauth_provider.rb', line 53 def access_token token = storage.get_token(server_url) logger.debug("OAuth access_token: retrieved token=#{token ? 'present' : 'nil'} for #{server_url}") return nil unless token # Return token if still valid return token unless token.expired? || token.expires_soon? # Try to refresh if we have a refresh token refresh_token(token) if token.refresh_token end |
#apply_authorization(request) ⇒ void
This method returns an undefined value.
Apply OAuth authorization to HTTP request
129 130 131 132 133 134 135 136 |
# File 'lib/mcp_client/auth/oauth_provider.rb', line 129 def (request) token = access_token logger.debug("OAuth apply_authorization: token=#{token ? 'present' : 'nil'}") return unless token logger.debug("OAuth applying authorization header: #{token.to_header[0..20]}...") request.headers['Authorization'] = token.to_header end |
#complete_authorization_flow(code, state) ⇒ Token
Complete OAuth authorization flow with authorization code
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
# File 'lib/mcp_client/auth/oauth_provider.rb', line 101 def (code, state) # Verify state parameter stored_state = storage.get_state(server_url) raise ArgumentError, 'Invalid state parameter' unless stored_state == state # Get stored PKCE and client info pkce = storage.get_pkce(server_url) client_info = storage.get_client_info(server_url) = raise MCPClient::Errors::ConnectionError, 'Missing PKCE or client info' unless pkce && client_info # Exchange authorization code for tokens token = (, client_info, code, pkce) # Store token storage.set_token(server_url, token) # Clean up temporary data storage.delete_pkce(server_url) storage.delete_state(server_url) token end |
#handle_unauthorized_response(response) ⇒ ResourceMetadata?
Handle 401 Unauthorized response (for server discovery)
141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/mcp_client/auth/oauth_provider.rb', line 141 def (response) www_authenticate = response.headers['WWW-Authenticate'] || response.headers['www-authenticate'] return nil unless www_authenticate # Parse WWW-Authenticate header to extract resource metadata URL # Format: Bearer resource="https://example.com/.well-known/oauth-protected-resource" if (match = www_authenticate.match(/resource="([^"]+)"/)) = match[1] () end end |
#start_authorization_flow ⇒ String
Start OAuth authorization flow
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
# File 'lib/mcp_client/auth/oauth_provider.rb', line 76 def # Discover authorization server = # Register client if needed client_info = get_or_register_client() # Generate PKCE parameters pkce = PKCE.new storage.set_pkce(server_url, pkce) # Generate state parameter state = SecureRandom.urlsafe_base64(32) storage.set_state(server_url, state) # Build authorization URL (, client_info, pkce, state) end |
#supported_scopes ⇒ Array<String>
Return the scopes supported by the authorization server Discovers server metadata and returns the scopes_supported list.
69 70 71 |
# File 'lib/mcp_client/auth/oauth_provider.rb', line 69 def supported_scopes @supported_scopes ||= .scopes_supported || [] end |