Understanding OAuth 2.0 Token Exchange
In modern software architectures, especially microservices-based systems, authentication is no longer a simple “login once, use everywhere” problem. A single access token is often expected to travel across multiple services, each with different responsibilities, trust boundaries, and security requirements.
This is the problem OAuth 2.0 Token Exchange (RFC 8693) was designed to solve. Instead of reusing one token everywhere, token exchange allows a system to transform an existing token into a new one, tailored for a specific service, audience, or context.
1. What is Token Exchange?
Token exchange is the process of exchanging an existing security token (usually an access token) for a new token intended for a different audience, scope, or service. Instead of reusing a single token across the entire system, token exchange enables generating tokens tailored to specific services, dynamically limiting their scopes based on context, maintaining the user’s identity throughout the flow, and preventing unnecessary exposure of tokens across multiple microservices.
In simple terms, one token comes in and is exchanged for a safer, more targeted token that is specifically tailored for a particular service or use case.
2. Why Token Exchange Matters in Modern Systems
Without token exchange, systems often rely on unsafe or inefficient patterns such as forwarding the same JWT across all services. This leads to security and architectural problems. Here is a breakdown of some of the reasons token exchange is important.
- Enforcing Least Privilege: A token issued for a frontend application might include broad scopes, such as
read:alloruser:*. If that same token is used inside backend microservices, it violates the principle of least privilege. Token exchange solves this by issuing a narrowly scoped token for each downstream service. - Preventing Token Leakage Across Services: In microservice architectures, multiple services may communicate internally. If the same token is reused everywhere, a compromise of one service could expose access to all others. Token exchange ensures each service receives a context-limited token that cannot be reused outside its intended scope.
- Improving Auditability and Traceability: Token exchange enables the creation of identity chains, where each newly issued token can carry metadata about the original issuer, the user’s identity, the acting service, and the intended target service, making auditing and traceability much more precise and reliable.
- Supporting Delegation and Service-to-Service Calls: A common requirement in distributed systems is for one service to call another on behalf of a user, and token exchange enables this by allowing the first service to obtain a new, service-specific token for the downstream service without directly passing along the original token.
3. OAuth 2.0 Token Exchange Overview (RFC 8693)
Token exchange is standardized under RFC 8693. It introduces a new grant type: urn:ietf:params:oauth:grant-type:token-exchange. The key idea is that a client presents an existing token to an authorization server and requests a new token that is specifically tailored for a particular audience or target service.
Token Exchange Request Structure
POST /oauth2/token Content-Type: application/x-www-form-urlencoded grant_type=urn:ietf:params:oauth:grant-type:token-exchange subject_token=eyJhbGciOiJSUzI1NiIs... subject_token_type=urn:ietf:params:oauth:token-type:access_token requested_token_type=urn:ietf:params:oauth:token-type:refresh_token audience=inventory-service scope=read:items
A token exchange request is sent to the authorization server’s token endpoint.
POST /oauth2/token Content-Type: application/x-www-form-urlencoded
grant_type
grant_type=urn:ietf:params:oauth:grant-type:token-exchange. This is the most important field. It tells the authorization server that this is not a normal login request, refresh request, or client credentials request.
Instead, it communicates that this is not a request for a fresh login, but rather a request to reuse an existing token and exchange it for another one, which helps eliminate ambiguity and ensures the authorization server applies strict validation rules designed specifically for token exchange flows.
subject_token
This is the original token that is being exchanged, and it represents the authenticated user or service, the initial security context under which the request was made, and the core identity information that must be preserved throughout the exchange process.
subject_token_type
This field indicates the type of token being supplied to the server, helping it interpret and process the request correctly, with common values including an access token, a JWT token, and less commonly a refresh token in token exchange scenarios.
requested_token_type
This parameter specifies the type of token the client is requesting from the authorization server, and in this case, it indicates that the client is asking for a refresh token. A refresh token is typically used to obtain new access tokens without requiring the user to re-authenticate, making it useful for long-lived sessions and background token renewal.
audience
This is one of the most critical elements in token exchange because it defines the intended recipient of the newly issued token by specifying “who this token is meant for,” and the audience value determines which service is permitted to accept the token, which API endpoints are authorized to process it, and how tightly the token’s scope is constrained to a specific target system.
scope
Scope defines what actions are allowed in the new token.
Token Exchange Response Structure
Once the authorization server validates the request, it issues a new token.
{
"access_token": "eyJhbGciOiJSUzI1NiIsNEW...",
"issued_token_type": "urn:ietf:params:oauth:token-type:access_token",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "read:items"
}
access_token
This is the newly issued token. It is scoped for the target service, signed by the authorization server, independent of the original token, and bound to a specific audience. Even though it is created from another token, it is a fully valid standalone credential.
issued_token_type
This indicates the type of token that was generated and helps clients know how to use the response, such as an access token for calling APIs, or an ID token for identity information in an OpenID Connect context.
token_type
This defines how the token should be used in HTTP requests, where a Bearer token means that anyone who has the token can use it to access protected resources.
expires_in
This defines how long the exchanged token remains valid (in seconds).
4. How to Implement Token Exchange
Implementation depends on your identity provider, but the general approach is consistent. At a high level, token exchange requires an OAuth 2.0–compliant authorization server that supports the RFC 8693 Token Exchange specification, along with properly configured clients and services that participate in the exchange flow.
Use an OAuth 2.0-Compliant Authorization Server
You need an identity provider that supports RFC 8693, such as Keycloak, Auth0 with extensions, Okta, or Spring Authorization Server. These providers allow a service to exchange an incoming access token for a new one with a different audience or scope, which is essential for secure service-to-service communication.
Register Clients for Token Exchange
Each participating service must be registered as a client in the authorization server. In addition to standard clients (e.g., browser-based apps), you need a dedicated client for token exchange.
A typical configuration (e.g., in Spring Authorization Server) looks like:
spring:
security:
oauth2:
authorizationserver:
client:
token-exchange-client:
registration:
client-id: "user-service"
client-secret: "{noop}token"
client-authentication-methods:
- "client_secret_basic"
authorization-grant-types:
- "urn:ietf:params:oauth:grant-type:token-exchange"
scopes:
- "message:read"
This configuration allows the user-service to request a new token on behalf of a user.
Enable Token Exchange Grant Type
The authorization server must explicitly support the token exchange grant type:
urn:ietf:params:oauth:grant-type:token-exchange
When making a token exchange request, the client includes the original user’s access token as the subject token, specifies the intended target service as the audience, and may optionally define scopes to limit the permissions of the newly issued token.
Configure Resource Servers to Validate Tokens
Each resource server must validate JWT tokens issued by the authorization server:
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: http://127.0.0.1:8001
audiences: order-service
This configuration tells Spring Security to validate JWT tokens issued by the authorization server running at http://127.0.0.1:8001. The audiences property is important because it enforces that only tokens meant for the order-service are accepted. This is critical in a token exchange flow, where different services receive tokens scoped specifically for them.
Summary of the Flow
- A user authenticates and receives an access token
- The client sends this token to Service A
- Service A exchanges the token for a new one targeting Service B
- Service A calls Service B using the exchanged token
- Service B validates the token and returns the requested data
This pattern ensures that each service receives a token scoped specifically for its needs, improving security and limiting token misuse across system boundaries.
5. Conclusion
In this article, we explored how token exchange works within the OAuth 2.0 framework. We examined how a token issued for one service can be securely exchanged for another token intended for a different audience, helping to enforce proper boundaries between services and ensuring that access is granted with the right level of trust and scope.
This article provides a guide to understanding token exchange.




