Token Exchange
The OAuth 2.0 Token Exchange (RFC 8693) is a standardized flow that allows a client to exchange one token for another. This is distinct from the standard OAuth authorization code or client credentials flows and is particularly useful in microservices architectures, token delegation scenarios, and when you need to transform tokens for different contexts.
Token Exchange enables various token transformation scenarios:
- Access Token β Access Token: Exchange an access token for another access token with different scopes (downscoping or upscoping)
- ID Token β Access Token: Exchange an ID token for an access token to access protected resources
- User Token β Service Token: Transform a user's access token into a service token for backend-to-backend communication
- Cross-Domain Token Exchange: Exchange tokens between different authorization servers or domains
Understanding Token Exchange vs. Other Flowsβ
It's important to understand that Token Exchange is not a standard OAuth authorization flow like Authorization Code or Client Credentials. Instead, it's a mechanism for transforming existing tokens. Here's how it compares:
| Flow | Purpose |
|---|---|
| Authorization Code | End-user sign-in + token creation |
| Client Credentials | Service authentication without user |
| Refresh Token | Get a new access token (same type/scope) |
| π Token Exchange | Convert existing tokens into new ones |
Key Difference: While other flows create tokens from credentials or authorization codes, Token Exchange transforms tokens you already have into different tokens with potentially different scopes, audiences, or types.
When to Use Token Exchangeβ
Token Exchange is ideal for:
- Microservices Architecture: Services need to exchange tokens to communicate with each other while maintaining user context
- Token Delegation: Delegating access from one service to another with appropriate scopes
- Scope Transformation: Downscoping (reducing permissions) or upscoping (requesting additional permissions) tokens
- Backend-for-Frontend (BFF) Pattern: Exchanging user tokens for service tokens in backend services
- Cross-Domain Scenarios: Exchanging tokens between different authorization servers or domains
- Token Refresh Alternatives: When you need a different token type rather than just refreshing the same token
Key Advantagesβ
- Token Transformation: Convert tokens between different types (access token, ID token, etc.)
- Scope Management: Adjust token scopes to match specific service requirements
- Audience Support: Request an
audienceso the exchanged tokenβsaudclaim is set to the target service/API, ensuring the token can only be used by that recipient - Delegation Support: Enable secure token delegation in distributed systems
- User Context Preservation: Maintain user context when exchanging tokens
- Flexible Architecture: Support complex microservices and multi-tenant scenarios
How it Worksβ
Before we step into how it works, let's understand some useful parameters.
| Parameter Name | Description |
|---|---|
grant_type | Must be urn:ietf:params:oauth:grant-type:token-exchange |
subject_token | The token you want to exchange (e.g., an access token, ID token) |
subject_token_type | Specifies the type of the token being exchanged. Common values: urn:ietf:params:oauth:token-type:access_token, urn:ietf:params:oauth:token-type:id_token |
scope | Optional. Defines the desired scopes for the new token. Used for downscoping or upscoping |
audience | Optional. Supported. Specifies the intended recipient(s) of the exchanged token. Can be a string (single audience) or an array of strings (multiple audiences). The issued tokenβs aud claim is set accordingly. See Audience (aud) in Token Exchange below. |
client_id | Client identifier (required in Authorization header or request body) |
client_secret | Client secret (required in Authorization header or request body) |
Audience (aud) in Token Exchangeβ
The audience (aud) in a token exchange identifies the intended recipient(s) of the exchanged token. When you include the audience parameter in the token exchange request, the authorization server issues a new token whose aud claim is set to that value. This ensures the token can only be used by the target service(s) or API(s) it was issued forβprotecting against token misuse and enabling strict audience validation in microservices and API gateways.
Format: audience can be either:
- String β single audience. The issued tokenβs
audclaim is a single value. Example:audience=api-backend-service - Array β multiple audiences. The issued tokenβs
audclaim is an array of those values. Inapplication/x-www-form-urlencodedrequests, send multiple values with the same parameter name:audience=api-a&audience=api-b
Step 1: The client application makes a POST request to the token endpoint with the subject_token (the token to be exchanged), subject_token_type, grant_type=urn:ietf:params:oauth:grant-type:token-exchange, and optionally scope and audience. The audience parameter is supported and sets the aud claim on the issued token so it can only be used by the target service/API.
Step 2: The authorization server validates:
- The
subject_tokenis valid and active - The client credentials (from Authorization header) are valid
- The requested scopes are allowed for the subject token
- The client has permission to perform token exchange
Step 3: If validation succeeds, the authorization server issues a new token (typically an access token) with the requested scopes and audience.
Step 4: The client uses the new token to access protected resources with the transformed permissions.
Technical Integrationβ
| API | Description | Link to API |
|---|---|---|
| Token Exchange | Exchange one token for another with potentially different scopes or audience. Supports the audience parameter so the issued tokenβs aud claim is set to the intended recipient (target service/API). | View API |
Example Implementationβ
Here are examples of common Token Exchange scenarios:
Example 1: Access Token β Access Token (Downscoping)β
Exchange a user's access token for a new access token with reduced scopes:
POST https://{{base_url}}/token-srv/token
Content-Type: application/x-www-form-urlencoded
Authorization: Basic {{base64_encoded_client_credentials}}
grant_type=urn:ietf:params:oauth:grant-type:token-exchange
&subject_token={{user_access_token}}
&subject_token_type=urn:ietf:params:oauth:token-type:access_token
&scope=read:data
&audience=api-backend-service
Response: The issued access token will include aud: "api-backend-service" when audience=api-backend-service was requested.
{
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "read:data",
"issued_token_type": "urn:ietf:params:oauth:token-type:access_token"
}
Example 2: ID Token β Access Tokenβ
Exchange an ID token for an access token. Include audience so the new token can only be used by the target API:
POST https://{{base_url}}/token-srv/token
Content-Type: application/x-www-form-urlencoded
Authorization: Basic {{base64_encoded_client_credentials}}
grant_type=urn:ietf:params:oauth:grant-type:token-exchange
&subject_token={{id_token}}
&subject_token_type=urn:ietf:params:oauth:token-type:id_token
&scope=api:read api:write
&audience=target-api-service
Example 3: User Token β Service Tokenβ
Transform a user's access token into a service token for backend communication:
POST https://{{base_url}}/token-srv/token
Content-Type: application/x-www-form-urlencoded
Authorization: Basic {{base64_encoded_service_client_credentials}}
grant_type=urn:ietf:params:oauth:grant-type:token-exchange
&subject_token={{user_access_token}}
&subject_token_type=urn:ietf:params:oauth:token-type:access_token
&scope=service:internal
&audience=internal-api-service
Base64 Encoding Exampleβ
To create the Authorization header, Base64-encode client_id:client_secret:
# Example: client_id="my-client-id", client_secret="my-client-secret"
# Encoded: bXktY2xpZW50LWlkOm15LWNsaWVudC1zZWNyZXQ=
Authorization: Basic bXktY2xpZW50LWlkOm15LWNsaWVudC1zZWNyZXQ=
JavaScript Example:
const credentials = btoa(`${client_id}:${client_secret}`);
const authHeader = `Basic ${credentials}`;
Security Considerationsβ
Security Noteβ
Important: Token Exchange should only be performed by confidential clients (server-side applications) that can securely store the
client_secret. Never perform token exchange from client-side code.
1. Confidential Client Requirementβ
- Only confidential clients (server-side applications) should perform token exchanges
- Ensure the
client_secretis securely stored and never exposed - Use environment variables or secret management systems
2. Authorization Header Securityβ
- The
Authorizationheader must include valid credentials (Base64-encoded client ID and secret) - If credentials are compromised, attackers can perform malicious token exchanges, leading to privilege escalation
- Always use HTTPS/TLS for all token exchange requests
3. Scope Restriction (Principle of Least Privilege)β
- Minimize the scope of the newly issued token to the least privilege required
- Use downscoping to reduce permissions when possible
- Avoid upscoping unless absolutely necessary and authorized
4. Subject Token Validationβ
- The Authorization Server validates the
subject_tokento ensure it is still active - The server verifies the token was issued to the correct client
- Expired or revoked tokens cannot be exchanged
5. Token Lifetime Managementβ
- Use short lifetimes for exchanged tokens to limit exposure
- Ensure exchanged tokens are only active for the required backend service "session"
- Implement proper token caching and expiration handling
6. Audit and Monitoringβ
- Log all token exchange requests for security auditing
- Monitor for unusual patterns (e.g., frequent exchanges, unexpected scope requests)
- Alert on failed exchange attempts or privilege escalation attempts
Common Use Casesβ
Use Case 1: Microservices Token Delegationβ
A frontend service receives a user's access token and needs to call a backend microservice. The frontend exchanges the user token for a service token with appropriate scopes for the microservice.
Use Case 2: Scope Downscopingβ
A user grants broad permissions to an application, but the application needs to call a third-party API with limited permissions. The application exchanges the broad-scope token for a narrow-scope token.
Use Case 3: Backend-for-Frontend (BFF) Patternβ
A BFF service receives user tokens from the frontend and exchanges them for service tokens to communicate with backend APIs, keeping the user context while using service credentials.
Use Case 4: Cross-Domain Token Exchangeβ
An application needs to access resources in a different domain. It exchanges its current token for a token valid in the target domain.
Comparison with Other Flowsβ
| Aspect | Token Exchange | Client Credentials | Authorization Code |
|---|---|---|---|
| User Interaction | β No | β No | β Yes |
| Client Secret | β Required | β Required | β Required |
| Use Case | Token transformation, delegation | M2M, Backend | User authentication |
| Input | Existing token | Client credentials | User credentials |
| Output | New token (different type/scope) | Access token | Access token |
| Best For | Microservices, token delegation | Server-to-server | User-facing apps |
Referencesβ
Need Support?β
Please contact us directly on our support page.