Token exchange example calls and responses

Example token exchange requests and responses demonstrate common scenarios, including scope reduction, audience changes, delegation, and claim mapping.

📘

For instructions on configuring the client, including allowed exchange types, authorization servers, audiences, resources, scopes, and claim mapping, see OIDC client (using the token exchange mechanism).

Scope reduction for downstream services

An application receives a broadly scoped access token from the login flow. Before calling a downstream microservice, it exchanges the token for one with a reduced set of scopes, following the principle of least privilege.

Configuration:

  • Allowed exchange: Delegation or impersonation.
  • Scopes: Restrict to read:orders.

Token exchange request

Original token with read:orders and read:profile scopes:

POST /oauth2/token
Content-Type: application/x-www-form-urlencoded
Authorization: Basic <client_credentials>

grant_type=urn:ietf:params:oauth:grant-type:token-exchange
&subject_token=eyJhbGciOi...originalToken...
&subject_token_type=urn:ietf:params:oauth:token-type:access_token
&scope=read:read:orders read:profile

Response

New token with only read:orders scope:

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

Audience change

A frontend application receives a token scoped for its own API (api.frontend.com). Before calling a partner service (api.partner.com), it exchanges the token for one with a new aud value.

Configuration

  • Allowed audiences: api.partner.com

Token exchange request

POST /oauth2/token
Content-Type: application/x-www-form-urlencoded
Authorization: Basic <client_credentials>

grant_type=urn:ietf:params:oauth:grant-type:token-exchange
&subject_token=eyJhbGciOi...originalToken...
&subject_token_type=urn:ietf:params:oauth:token-type:access_token
&audience=api.partner.com

Response

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

Decoded JWT payload

{
  "sub": "user_123",
  "aud": "api.partner.com",
  "scope": "",
  "iss": "{issuer}",
  "iat": 1724487400,
  "exp": 1724491000
}

Delegation (act-as)

A support dashboard application allows agents to act on behalf of customers to perform troubleshooting. The agent’s client uses token exchange to produce a delegated token with an `act' claim representing the customer.

Policy settings

  • Allowed exchange type: Delegation.
  • Allowed authorization servers: Must accept both subject and actor tokens from trusted issuers.
  • Scope handling: May be restricted to limited scopes (e.g., support:read).
  • Claim mapping: Optional, policies can forward or transform claims from either token.

Token inputs

Subject token (Decoded JWT Payload)

Represents the end user (customer):

{
  "sub": "user_123",
  "email": "[email protected]",
  "tenant_id": "acme",
  "iss": "https://login.strivacity.com",
  "iat": 1724487600,
  "exp": 1724491200
}

Actor Token (Decoded JWT payload)

Represents the support agent:

{
  "sub": "support_agent_456",
  "email": "[email protected]",
  "role": "support",
  "iss": "https://login.strivacity.com",
  "iat": 1724487650,
  "exp": 1724491250
}

Token exchange request

Request includes the JWT subject token and actor token to use in the resulting delegated token.

POST /oauth2/token
Content-Type: application/x-www-form-urlencoded
Authorization: Basic <client_credentials>

grant_type=urn:ietf:params:oauth:grant-type:token-exchange&
subject_token=eyJhbGciOi...subjectToken...&
subject_token_type=urn:ietf:params:oauth:token-type:access_token&
actor_token=eyJhbGciOi...actorToken...&
actor_token_type=urn:ietf:params:oauth:token-type:access_token

Response (token exchange output)

Response is a bearer token with an access token in the JWT payload:

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

Resulting access token (decoded JWT payload)

The resulting access token includes the support agent’s identifier as the root “sub” claim and the customer's identifier in the “sub” claim under the “act” claim.

{
  "sub": "support_agent_456",
  "scope": "support:read user:read",
  "tenant_id": "acme",
  "act": {
    "sub": "user_123"
  },
  "iss": "https://login.strivacity.com",
  "iat": 1724487700,
  "exp": 1724491300
}

Claim mapping

Claim mapping allows you to modify or enrich the token claims in the resulting token during exchange. The claim mapping code block allows for mapping data into the new token from:

  • The original token
  • From an identity store
  • From a 3rd party data source

Response 200 from claim mapping

Claim mapping code

module.exports = async function ({ request_body, requested_scopes, account }) {
  return new ClaimMapping({ custom: "data" });
}; 

Content of the token in response

"custom": "data" appears at top level

{
  "aud": [
    "hodor"
  ],
  "client_id": "d3b7292ee8594f97a255d7c7c0221071",
  "custom": "data",
  "exp": 1753346210,
  "ext": {
    "given_name": "2188e297-780e-4ed4-b342-706378def084"
  },
  "given_name": "2188e297-780e-4ed4-b342-706378def084",
  "iat": 1753342610,
  "iss": "https://demo.strivacity.cloud/",
  "jti": "74873dfa-5c20-4d43-b64e-3e0c9d0117b2",
  "may_act": {
    "sub": "d3b7292ee8594f97a255d7c7c0221071"
  },
  "nbf": 1753342610,
  "scp": [

Did this page help you?