Module: MCP::Client::OAuth::IDJAGTokenExchange

Defined in:
lib/mcp/client/oauth/id_jag_token_exchange.rb

Overview

RFC 8693 token exchange against an enterprise identity provider, turning an IdP-issued ID token into an Identity Assertion Authorization Grant (ID-JAG) per the MCP Enterprise Managed Authorization extension (SEP-990). The returned ID-JAG is an opaque assertion the client then presents to the MCP authorization server with the RFC 7523 jwt-bearer grant (see CrossAppAccessProvider). Mirrors requestJwtAuthorizationGrant in the TypeScript SDK.

Defined Under Namespace

Classes: ExchangeError

Constant Summary collapse

GRANT_TYPE =
"urn:ietf:params:oauth:grant-type:token-exchange"
ID_TOKEN_TYPE =
"urn:ietf:params:oauth:token-type:id_token"
ID_JAG_TOKEN_TYPE =
"urn:ietf:params:oauth:token-type:id-jag"

Class Method Summary collapse

Class Method Details

.request(token_endpoint:, id_token:, client_id:, audience:, resource:, http_client: nil) ⇒ Object

Exchanges id_token for an ID-JAG at the IdP's token endpoint and returns the assertion string.

Parameters:

  • token_endpoint (String)

    The identity provider's token endpoint.

  • id_token (String)

    The IdP-issued ID token (the subject token).

  • client_id (String)

    The client's identifier at the IdP.

  • audience (String)

    The MCP authorization server's issuer identifier.

  • resource (String)

    The canonical MCP server URL (RFC 8707).

  • http_client (Object, nil) (defaults to: nil)

    Faraday-compatible client; built lazily by default.



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/mcp/client/oauth/id_jag_token_exchange.rb', line 34

def request(token_endpoint:, id_token:, client_id:, audience:, resource:, http_client: nil)
  http_client ||= default_http_client

  response = begin
    http_client.post(token_endpoint) do |req|
      req.headers["Content-Type"] = "application/x-www-form-urlencoded"
      req.headers["Accept"] = "application/json"
      req.body = URI.encode_www_form(
        "grant_type" => GRANT_TYPE,
        "subject_token" => id_token,
        "subject_token_type" => ID_TOKEN_TYPE,
        "requested_token_type" => ID_JAG_TOKEN_TYPE,
        "audience" => audience,
        "resource" => resource,
        "client_id" => client_id,
      )
    end
  rescue Faraday::Error => e
    raise ExchangeError, "Token exchange request to #{token_endpoint} failed: #{e.class}: #{e.message}."
  end

  if response.status < 200 || response.status >= 300
    raise ExchangeError, "Identity provider token exchange returned status #{response.status}."
  end

  parse_id_jag(response)
end