Skip to main content

Token Exchange

Token Exchange (RFC 8693) lets a client present an existing token to ThunderID and request a different token in return. The exchanged token can be bound to a target resource server, carry narrower scopes, or represent an "on-behalf-of" act in a service-to-service call chain.

Typical uses:

  • A frontend exchanges a user's access token for a downscoped token before passing it to a third-party API.
  • A gateway exchanges an inbound token for a service-mesh token whose aud matches a downstream resource server.
  • A backend acts on behalf of a user it received an id_token for, asking ThunderID to mint an access token for that user against a specific resource server.

How It Works

How ThunderID Implements It
AspectBehavior
EndpointPOST /oauth2/token
Grant typeurn:ietf:params:oauth:grant-type:token-exchange
subject_token_type (input)urn:ietf:params:oauth:token-type:access_token · :refresh_token · :id_token · :jwt
actor_token_type (input)Same set as subject_token_type; used for delegation chains
requested_token_type (output)urn:ietf:params:oauth:token-type:access_token · :jwt only. id_token and refresh_token outputs are not supported.
audience parameterAccepted for RFC 8693 compatibility but does not determine the issued access token's aud claim
resource parameterRFC 8707 resource indicator. The issued access token is bound to exactly this resource server. Permission-bearing requests use defaultResourceServer when it is omitted. OIDC-only or scopeless requests use the application's token.accessToken.defaultAudience, falling back to client_id
scope parameterRequested scopes; downscoping is allowed, widening is rejected with invalid_scope. Final scopes must also be permissions on the target resource server and authorized for the issuing app or agent.
Client authenticationRequired, same methods as the token endpoint
Issued token shapeissued_token_type is echoed in the response so the caller knows what it received

Request Fields

FieldRequiredDescription
grant_typeYesurn:ietf:params:oauth:grant-type:token-exchange
subject_tokenYesThe token being exchanged
subject_token_typeYesThe type URI of subject_token
requested_token_typeNoDefaults to :access_token
actor_tokenNoToken of the acting party in delegation
actor_token_typeNoRequired when actor_token is supplied
audienceNoLogical audience value from RFC 8693. It is ignored for the access-token aud; use resource to select the token audience.
resourceNoAbsolute URI of the target resource server (see Resource Indicators). If omitted, permission-bearing requests use the configured default resource server, while OIDC-only or scopeless requests use the application's token.accessToken.defaultAudience, falling back to client_id.
scopeNoRequested scopes must be a subset of the subject token's grant

Try It in ThunderID

  1. Open Applications or Agents in the ThunderID Console and select the client that will perform the exchange.
  2. Open the Advanced Settings tab.
  3. Under Grant Types, add urn:ietf:params:oauth:grant-type:token-exchange.
  4. Save.

Exchange a Token

curl -X POST https://thunderid.example.com/oauth2/token \
-u "$CLIENT_ID:$CLIENT_SECRET" \
-d "grant_type=urn:ietf:params:oauth:grant-type:token-exchange" \
-d "subject_token=$ACCESS_TOKEN" \
-d "subject_token_type=urn:ietf:params:oauth:token-type:access_token" \
-d "resource=https://api.example.com/payments" \
-d "scope=payments:read"

Response:

{
"access_token": "eyJhbGciOi...",
"issued_token_type": "urn:ietf:params:oauth:token-type:access_token",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "payments:read"
}

Explore with AI

ThunderID LogoThunderID Logo

Product

DocsAPIsSDKs
© Copyright Linux Foundation Europe.For web site terms of use, trademark policy and other project policies please see https://linuxfoundation.eu/en/policies.