Class: MCP::Client::OAuth::ClientCredentialsProvider
- Inherits:
-
Object
- Object
- MCP::Client::OAuth::ClientCredentialsProvider
- Includes:
- StorageBackedProvider
- Defined in:
- lib/mcp/client/oauth/client_credentials_provider.rb
Overview
OAuth client configuration for the OAuth 2.1 client_credentials grant
(machine-to-machine, no user and no browser redirect). Handed to
MCP::Client::HTTP via the oauth: keyword, the same as Provider.
The interactive Authorization Code flow lives in Provider;
this class exists so a credentials-only client never has to supply
the redirect arguments that grant has no use for, mirroring the dedicated
ClientCredentialsProvider in the TypeScript SDK and
ClientCredentialsOAuthProvider in the Python SDK.
Required keyword arguments:
client_id- String identifying the pre-registered confidential client.client_secret- String shared secret for theclient_secret_basic/client_secret_postmethods. Theclient_credentialsgrant is for confidential clients, so a credential is mandatory; withprivate_key_jwtthe credential is theprivate_keyinstead.
Optional keyword arguments:
token_endpoint_auth_method-"client_secret_basic"(default),"client_secret_post", or"private_key_jwt"(RFC 7523 JWT client assertion, per theio.modelcontextprotocol/oauth-client-credentialsextension / SEP-1046)."none"is rejected: an unauthenticatedclient_credentialsrequest is meaningless.private_key- PEM string (orOpenSSL::PKey::PKey) used to sign the JWT client assertion. Required withprivate_key_jwt. The key is held on the provider and never written tostorage.signing_algorithm-"ES256"or"RS256". Required withprivate_key_jwt; there is no default, so a mismatch with the server'stoken_endpoint_auth_signing_alg_values_supportedfails loudly at construction instead of as a 401 (the TypeScript and Python SDKs also take the algorithm as an explicit option).scope- String of space-separated scopes to request when the server'sWWW-Authenticateand the Protected Resource Metadata do not specify one.storage- Object responding totokens,save_tokens(tokens),client_information, andsave_client_information(info). Defaults to anInMemoryStorage. Theclient_id/client_secretare written into it so the token exchange reads them through the same path as a pre-registered authorization-code client.
Defined Under Namespace
Classes: InvalidCredentialsError
Constant Summary collapse
- SUPPORTED_AUTH_METHODS =
["client_secret_basic", "client_secret_post", "private_key_jwt"].freeze
Instance Attribute Summary collapse
-
#scope ⇒ Object
readonly
Returns the value of attribute scope.
-
#storage ⇒ Object
readonly
Returns the value of attribute storage.
Instance Method Summary collapse
-
#authorization_flow ⇒ Object
See
Provider#authorization_flow. -
#client_assertion(audience:) ⇒ Object
Returns a freshly signed RFC 7523 JWT client assertion for the
private_key_jwtmethod. -
#initialize(client_id:, client_secret: nil, token_endpoint_auth_method: "client_secret_basic", private_key: nil, signing_algorithm: nil, scope: nil, storage: nil) ⇒ ClientCredentialsProvider
constructor
A new instance of ClientCredentialsProvider.
Methods included from StorageBackedProvider
#access_token, #clear_tokens!, #client_information, #save_client_information, #save_tokens, #tokens
Constructor Details
#initialize(client_id:, client_secret: nil, token_endpoint_auth_method: "client_secret_basic", private_key: nil, signing_algorithm: nil, scope: nil, storage: nil) ⇒ ClientCredentialsProvider
Returns a new instance of ClientCredentialsProvider.
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
# File 'lib/mcp/client/oauth/client_credentials_provider.rb', line 56 def initialize( client_id:, client_secret: nil, token_endpoint_auth_method: "client_secret_basic", private_key: nil, signing_algorithm: nil, scope: nil, storage: nil ) if blank?(client_id) raise InvalidCredentialsError, "client_id is required for the client_credentials grant." end unless SUPPORTED_AUTH_METHODS.include?(token_endpoint_auth_method) raise InvalidCredentialsError, "token_endpoint_auth_method must be one of #{SUPPORTED_AUTH_METHODS.inspect} for the " \ "client_credentials grant (got #{token_endpoint_auth_method.inspect}); an unauthenticated " \ "client_credentials request is not allowed." end client_information = { "client_id" => client_id, "token_endpoint_auth_method" => token_endpoint_auth_method } if token_endpoint_auth_method == "private_key_jwt" validate_private_key_jwt_arguments!( client_secret: client_secret, private_key: private_key, signing_algorithm: signing_algorithm, ) # Fail fast on an unparseable key or a key/algorithm mismatch by # signing a throwaway assertion now rather than at token time. JWTClientAssertion.generate( client_id: client_id, audience: "urn:mcp:credential-validation", private_key: private_key, signing_algorithm: signing_algorithm, ) else if blank?(client_secret) raise InvalidCredentialsError, "client_secret is required for the client_credentials grant with #{token_endpoint_auth_method}." end client_information["client_secret"] = client_secret end @client_id = client_id @private_key = private_key @signing_algorithm = signing_algorithm @scope = scope @storage = storage || InMemoryStorage.new @storage.save_client_information(client_information) end |
Instance Attribute Details
#scope ⇒ Object (readonly)
Returns the value of attribute scope.
54 55 56 |
# File 'lib/mcp/client/oauth/client_credentials_provider.rb', line 54 def scope @scope end |
#storage ⇒ Object (readonly)
Returns the value of attribute storage.
54 55 56 |
# File 'lib/mcp/client/oauth/client_credentials_provider.rb', line 54 def storage @storage end |
Instance Method Details
#authorization_flow ⇒ Object
See Provider#authorization_flow.
110 111 112 |
# File 'lib/mcp/client/oauth/client_credentials_provider.rb', line 110 def :client_credentials end |
#client_assertion(audience:) ⇒ Object
Returns a freshly signed RFC 7523 JWT client assertion for the private_key_jwt method.
audience is the authorization server's issuer identifier. Called by Flow#post_to_token_endpoint.
116 117 118 119 120 121 122 123 |
# File 'lib/mcp/client/oauth/client_credentials_provider.rb', line 116 def client_assertion(audience:) JWTClientAssertion.generate( client_id: @client_id, audience: audience, private_key: @private_key, signing_algorithm: @signing_algorithm, ) end |