OAuth Token Exchange
OAuth Token Exchange lets you swap one access token for another. This is useful when you need different permissions or want to safely pass tokens between services.
Why use token exchange?
In modern applications, services often need to call other services, but you don't always want to pass around your full token. Token exchange solves common problems:
-
Too many permissions: Your token has broad access, but the downstream service only needs specific permissions.
-
Passport token: Your single-page app needs only limited scopes, but your API gateway exchanges these tokens for specific backends with specific scopes and audiences.
-
External tokens: You have a token from Azure AD or Google, but need one from your own system.
This follows the principle of least privilege, which is a security practice that provides only the minimum permissions that are needed.
How token exchange works
Token exchange follows RFC 8693. You send your current token and get a new token back with different properties.
Token exchange follows a basic flow:
-
You have an access token.
-
You request a new token with reduced scopes or a different audience.
-
The system validates your original token.
-
You get back a new token with the requested changes.
Requirements for token exchange
-
Only JWT tokens are supported as subject tokens (no opaque tokens).
-
Only impersonation is supported (no delegation or actor_tokens).
-
You can only exchange access tokens for access tokens (the OneWelcome Identity Platform doesn't issue ID tokens or refresh tokens).
-
The new token cannot be valid for longer than the original token.
-
Access tokens created through token exchange cannot be revoked.
Token exchange use cases
The OneWelcome Identity Platform supports two main scenarios for token exchange:
1. Access token to access token
Use this when you need to exchange tokens between web clients within the same tenant, allowing for different scopes or audiences.
Example: Client A issued a token, and Client B needs to exchange it for a token with its own configured scopes and audiences.
Configuration:
-
Add the Token exchange grant to the web client.
-
In the
Token Exchangesection, select the use case: Access token to access token. -
Optionally, configure a web hook.
Rules:
-
It works only if the
clientIdof the client that performs the exchange is listed as an audience in the subject token, or is the original client that requested the token. -
Only scopes and audiences configured for the client are allowed to be requested via token exchange.
-
A new token cannot be valid for longer than the original. It also cannot be valid for longer than the access token validity of the client that performs the exchange (the shortest validity of the two is used).
-
Logging out the original token also invalidates the exchanged tokens.
-
User Claims from the original token are duplicated in the exchanged token. Required claims from the JWT access token data structure can be overwritten.
-
The OneWelcome Identity Platform checks whether the subject token is still valid (not revoked) before exchanging it for another token.
Token chain management
Since the OneWelcome Identity Platform issues both the subject tokens and the exchanged tokens, it has additional protection built in. Token exchange creates parent-child relationships between tokens. You can exchange an already-exchanged token, which creates chains like: Token A → Token B → Token C.
Logout and revocation behavior:
-
End session (
/oauth/v1/logout): Requires the ID token hint of the parent token and invalidates the entire token chain. -
Revocation (
/oauth/v1/revoke): -
Revoking a parent token invalidates the entire chain of children (cascading revocation).
-
Revoking a child token invalidates only that child token and any tokens derived from it.
This follows RFC 7009, which states that revocation "will invalidate the actual token and, if applicable, other tokens based on the same authorization grant".
Session tracking: Clients that performed token exchange appear in the user sessions list under /oauth/api/v1/users/{userId}/sessions/{sessionId}.
2. Exchange external identity provider tokens
Use this when you have tokens from external identity providers (IDP) like Azure AD or SafeNet Trusted Access (STA), but need tokens from our system.
Configuration:
-
In your external IDP, ensure that the issuer URI of your tenant is registered as an
audienceof the token that you want to exchange (for example:https://auth.example.com/oauth). -
Add the token exchange grant to the web client.
-
In the
Token Exchangesection, select the use case: External access token to access token. -
Configure the external IDP:
- Issuer
- JWKS URI
-
Optionally, configure a web hook.
-
Ensure that you configure the scopes, audiences, and token validity that you require. The OneWelcome Identity Platform uses this configuration to ensure that it limits the tokens that it issues.
Rules:
-
Your tenant's issuer URI must be listed in the audience of the external token.
-
It accepts only JWT access tokens from external IDPs.
-
It supports one external IDP per client configuration.
-
User Claims from the original token are copied in the exchanged token. Required claims from the JWT access token data structure can be overwritten.
-
A new token cannot be valid for longer than the original. It also cannot be valid for longer than the access token validity of the client that does the exchange.
-
Only scopes and audiences that are configured for the client are allowed to be requested via token exchange.
Token exchange request
Send a POST request to your token endpoint with these parameters:
grant_type=urn:ietf:params:oauth:grant-type:token-exchange
subject_token=<your_current_token>
subject_token_type=urn:ietf:params:oauth:token-type:access_token
requested_token_type=urn:ietf:params:oauth:token-type:access_token
scope=<optional_reduced_scopes>
audience=<optional_target_audience>
Custom logic with web hooks
For advanced scenarios, you can add custom logic using web hooks. The web hook receives details about the token exchange and can do the following:
-
Deny the exchange.
-
Remove specific scopes.
-
Add custom claims to the new token.
Web hook request
Your web hook receives a POST request with the following information:
{
"clientId": "your-client-id",
"scopes": ["read", "write"],
"audience": ["api.example.com"],
"resources": ["https://api.example.com"],
"requestedTokenType": "urn:ietf:params:oauth:token-type:access_token",
"subject": {
"subjectToken": "eyJ...",
"tokenType": "urn:ietf:params:oauth:token-type:access_token",
"decodedClaims": {
"sub": "user123",
"scope": "read write"
}
}
}
Web hook response
{
"denyExchange": false,
"removeScopes": ["write"],
"claims": {
"department": "engineering",
"role": "developer"
}
}
The following claims are considered protected and are not allowed to be modified via the web hook:
- iss
- aud
- verified_claims
- sub
- urn:onegini.com:oidc:*
- group_permissions
Security notes
-
New tokens are never more powerful than the original token.
-
Token validity is capped by the original token's expiration.
-
External tokens are fully validated before the exchange.
-
All exchanges are logged with appropriate event types.
Client credentials support
Yes, you can exchange client credentials tokens. The same rules apply, you can only reduce permissions, not expand them. Revoking the original client credentials access token does not impact the validity of the exchanged tokens.
Common questions
Q: What if I don't specify an audience in my token exchange request?
A: You get the default audience configured for your client.
Q: What if I don't specify scopes in my token exchange request?
A: You get the default scopes configured for your client.
Q: Can I exchange a token from Client A using Client B?
A: Yes, but only if Client B's clientId is listed as an audience in the subject token from Client A.
Q: Do access token hooks run during token exchange?
A: No, regular access token hooks don't run during token exchange. Use the token exchange web hook for custom logic.
Q: What happens if I revoke a token in the middle of a chain?
A: Revoking a token invalidates that token and all tokens derived from it (its children), but leaves parent tokens unaffected.