Module: MCP::Client::OAuth::JWTClientAssertion
- Defined in:
- lib/mcp/client/oauth/jwt_client_assertion.rb
Overview
Builds RFC 7523 Section 2.2 JWT client assertions for the private_key_jwt
client authentication method used by the client_credentials grant
(MCP extension io.modelcontextprotocol/oauth-client-credentials, SEP-1046).
The JWS is assembled with openssl so the SDK stays free of a JWT gem dependency
(the TypeScript and Python SDKs use jose and PyJWT for the same assertion).
Claims follow SEP-1046 and RFC 7523: iss and sub carry the client_id,
aud carries the authorization server's issuer identifier, plus exp, iat,
and a unique jti.
Defined Under Namespace
Classes: InvalidKeyError, UnsupportedAlgorithmError
Constant Summary collapse
- ASSERTION_TYPE =
RFC 7523 Section 2.2
client_assertion_typevalue. "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"- DEFAULT_LIFETIME =
Assertion lifetime in seconds; matches the TypeScript SDK's
jwtLifetimeSecondsand the Python SDK'slifetime_secondsdefault. 300- SUPPORTED_ALGORITHMS =
["ES256", "RS256"].freeze
Class Method Summary collapse
-
.generate(client_id:, audience:, private_key:, signing_algorithm:, lifetime: DEFAULT_LIFETIME) ⇒ Object
Returns a signed compact-serialization JWT (
header.payload.signature).
Class Method Details
.generate(client_id:, audience:, private_key:, signing_algorithm:, lifetime: DEFAULT_LIFETIME) ⇒ Object
Returns a signed compact-serialization JWT (header.payload.signature).
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
# File 'lib/mcp/client/oauth/jwt_client_assertion.rb', line 54 def generate(client_id:, audience:, private_key:, signing_algorithm:, lifetime: DEFAULT_LIFETIME) unless SUPPORTED_ALGORITHMS.include?(signing_algorithm) raise UnsupportedAlgorithmError, "signing_algorithm must be one of #{SUPPORTED_ALGORITHMS.inspect} (got #{signing_algorithm.inspect})." end key = parse_key(private_key) validate_key!(key, signing_algorithm) now = Time.now.to_i header = { alg: signing_algorithm, typ: "JWT" } claims = { iss: client_id, sub: client_id, aud: audience, exp: now + lifetime, iat: now, jti: SecureRandom.uuid, } signing_input = "#{base64url(JSON.generate(header))}.#{base64url(JSON.generate(claims))}" "#{signing_input}.#{base64url(sign(key, signing_algorithm, signing_input))}" end |