πͺπΈOAuth2 Token Exchange Lab
π― Objective
The goal of this lab is to demonstrate the OAuth2 Token Exchange feature in Spring Security and Spring Authorization Server.
What is OAuth2 Token Exchange
According to oauth.net, the Token Exchange extension defines a mechanism for a client to obtain its own tokens given a separate set of tokens. This has several different applications, including:
Single-sign-on between multiple mobile apps without launching a web browser
A resource server exchanging a client's tokens for its own tokens
The OAuth 2.0 Token Exchange (RFC 8693) defines how to request and obtain security tokens from OAuth 2.0 authorization servers, including security tokens employing impersonation and delegation.
The analogy between impersonation and delegation is similar to the difference between a user impersonating another user and a user delegating their authority to another user.
Real-world metaphor
Pretending to be someone else
Acting with someone's permission
Actor identity
Hidden (disguised as the subject)
Transparent (both actor and subject known)
Audit logs
Show only the impersonated user
Show both the original and delegated user
Power analogy
Borrowing someone's ID
Acting under power of attorney
Common association
βLogin as userβ in admin panels
Service A calling Service B for User X
The OAuth 2.0 Token Exchange (RFC 8693) extension defines a mechanism for a client to obtain its own tokens given a separate set of tokens. This has several different applications, including:
Definition
Acting as another user
Acting on behalf of another user
Identity in token
Subject only (sub = user)
Subject + Actor (sub = user, act = caller)
Who appears to act
The impersonated user
The original caller
Access Rights
Fully inherit target user's rights
Target user's rights, caller identity preserved
Audit Visibility
Limited β only the impersonated user
Full β both subject and actor are visible
Use Case Example
Admin logs in as user
API calling downstream with user context
Security Risk
Higher (hides true actor)
Lower (identity chain is preserved)
Step 1: Having a look into the provided code
This repository directory token-exchange contains all required component apps of the OAuth2 Token Exchange lab implemented with Spring Security and Spring
Authorization Server.
It includes four modules:
spring-authorization-server: A Spring Boot application that acts as an OAuth2 authorization server. It is pre-configured with the required endpoints and client registrations.
token-exchange-client: A Spring Boot application that acts as an OAuth2 client.
token-exchange-resource-server: A Spring Boot application that acts as an OAuth2 resource server performing the token exchange and then calls the final target resource server.
target-resource-server: A Spring Boot application that acts as a target resource server that is called with the exchanged token.
To implement OAuth2 Token Exchange, you require at least:
Details on implementing the OAuth2 Token Exchange feature using Spring Security can be found in the Spring Security Reference.
Scenario

The scenario that will be implemented is as follows:
The client application (http://localhost:8080) requests an access token from the authorization server (http://localhost:9000).
The client application uses the access token to call the first resource server (http://localhost:9091).
The first resource server performs a token exchange with the authorization server (http://localhost:9000) to get a new access token for the target resource server (http://localhost:9092).
The target resource server (http://localhost:9092) when called with the exchanged access token, will check for expected audience claim value.
http://localhost:9000
Spring Authorization Server
The Authorization Server issuing all tokens
http://localhost:8080/client
OAuth2 Client Application
The client application triggering the flow by logging in to the Authorization Server and calling the first resource server
http://localhost:9091
Token Exchange Resource Server
The first resource server being called by the client and performing the token exchange before calling the target resource server
http://localhost:9092
Target Resource Server
The final target resource server being called with the exchanged token
Step 2: The Spring Authorization Server
The Spring Authorization Server is pre-configured with the required endpoints and client registrations.
Configuration
The following OAuth2 client registrations are configured:
messaging-client: This client is used to authenticate the user and retrieve an access token for the first resource server. This client is configured as a public client and uses the authorization code grant type including Proof Key for Code Exchange (PKCE).
token-exchange-client: This client is used by the first resource server to perform the token exchange with the authorization server
You can look up the client registrations in the SingleTenantClientConfiguration class:
The OAuth2 Token Exchange is this lab performs an impersonation of the user adding access rights for the API of the target resource server (see the audience claim).
The audience claim is used to identify the target resource server that is being called with the exchanged token. The audience claim is a list and is set to the API resources of the target resource server.
The audience claim is also set in the SingleTenantClientConfiguration class (in addition, it also sets the roles claim):
Run the Spring Authorization Server
Start the Spring Authorization Server by running the SpringAuthorizationServerApplication class in your IDE or using the Maven Spring Boot plugin.
The Spring Authorization Server will be available at http://localhost:9000. You can check if the authorization server is running by opening the following URL in your browser: OpenID Configuration.
In case you are using IntelliJ IDEA, you can also use the provided Http Client to test the authorization server located in folder labs/token-exchange/spring-authorization-server/requests.
Step 3: The OAuth2 Client Application
The OAuth2 Client Application is a Spring Boot application that acts as an OAuth2 client. It is responsible for authenticating the user and retrieving an access token for the first resource server (token exchange resource server).
The client application is pre-configured with the required endpoints and client registrations.
Configuration and provided APIs
The following OAuth2 client registrations are configured in the application.yml file:
The corresponding OAuth2 client authentication is configured in the WebSecurityConfiguration class:
The client application is pre-configured with the following endpoints:
/api/hello: The login page for the client application. This page is used to authenticate the user and retrieve an access token for the first resource server.
The corresponding rest controller is implemented in the ClientApi class:
This is an implementation of the OAuth 2.0 βToken Relayβ pattern, where:
The client authenticates the user
The client uses the userβs token to call a downstream resource server on their behalf with the Spring Rest Client.
@RegisteredOAuth2AuthorizedClient
Retrieves current user's OAuth2 access token. If no token is available it triggers the OAuth2 Authorization Code + PKCE flow using the messaging-client-oidc client
RestClient with Bearer token
Sends the token to another secured downstream service (the token exchange resource server)
Endpoint /api/hello
Returns the response from the protected API
Run the OAuth2 Client Application
Start the OAuth2 Client Application by running the TokenExchangeClientApplication class in your IDE or using the Maven Spring Boot plugin.
The OAuth2 Client Application will be available at http://localhost:8080/client. If you navigate to this address in your browser, you will be redirected to the login page of the authorization server. Please do not continue at this point. We will continue from this point in the next steps.
Step 4: The Target Resource Server
The target resource server is a Spring Boot application that acts as a target resource server that is called with the exchanged token.
Configuration and provided APIs
The target resource server is configured to validate the exchanged token with the public key from the issuer at http://localhost:9000 and check for the expected audience claim value http://localhost:9092/api/messages. This is done in the application.yml file:
The corresponding configuration code to enable JWT validation is implemented in the WebSecurityConfiguration class:
In summary, the configuration of the target resource server is as follows:
Configures the application as a resource server that validates JWTs.
issuer-uri: The URL of the OAuth 2.0 authorization server (usually the OpenID Provider).
Spring uses this to:
Automatically discover the public key (/.well-known/openid-configuration)
Validate the signature of incoming JWTs with the public key
Validate the iss (issuer) claim in incoming JWTs
Validate aud (audience) claim in incoming JWTs
β
Expected: The target resource server does only accept exchanged tokens with the audience claim set to http://localhost:9092/api/messages and no tokens provided directly from the client application.
Run the Target Resource Server
Start the Target Resource Server by running the TargetResourceServerApplication class in your IDE or using the Maven Spring Boot plugin.
The Target Resource Server will be available at http://localhost:9092/api/messages. You can check if the target resource server is running by opening the following URL in your browser: http://localhost:9092/api/messages. Expect a 401 Unauthorized error, as the target resource server is configured to require a valid JWT token for access.
Step 5: The Token Exchange Resource Server
Finally, the token exchange resource server is a Spring Boot application that acts as an OAuth2 resource server performing the token exchange and then calls the final target resource server (the target resource server we just have started).
Here you will add the finalizing code to perform the token exchange with the authorization server and call the target resource server with the exchanged token.
Configuration and provided APIs
The token exchange resource server is configured to validate the exchanged token with the public key from the issuer at http://localhost:9000 and check for the expected audience claim value http://localhost:9092/api/messages. This is done in the application.yml file:
The corresponding configuration code to enable JWT validation is implemented in the WebSecurityConfiguration class:
Run the Token Exchange Resource Server
Start the Token Exchange Resource Server by running the TokenExchangeResourceServerApplication class in your IDE or using the Maven Spring Boot plugin.
The Token Exchange Resource Server will be available at http://localhost:9091/api/messages. You can check if the token exchange resource server is running by opening the following URL in your browser: http://localhost:9091/api/messages. Expect a 401 Unauthorized error, as the token exchange resource server is configured to require a valid JWT token for access.
Try the complete flow
As we started all the applications, we can now try the complete flow.
Open your browser and navigate to http://localhost:8080/client.
You will be redirected to the login page of the authorization server.
Log in with the user credentials
user/password.You will be redirected back to the client application and see a greeting message, but it will not show the message from the target resource server. That is because it just uses the token from the client application to call the target resource server.
Step 6: Configure and Perform the Token Exchange
The token exchange resource server must be configured to perform the token exchange with the authorization server and call the target resource server with the exchanged token.
Enable the Token Exchange capability
First, we need to add the Spring Security components required to perform the token exchange. This is done in the WebSecurityConfiguration class:
π§ Purpose of the OAuth2AuthorizedClientManager Bean
OAuth2AuthorizedClientManager is used to manage OAuth 2.0 clients, typically to:
Automatically acquire or refresh tokens,
Perform token exchanges,
Handle the persistence of authorized clients.
π What This Specific Code Does
Creates a provider that knows how to perform OAuth 2.0 Token Exchange:
Builds an OAuth2AuthorizedClientProvider with only token exchange capabilities.
You could also include other providers here (e.g., refresh_token, client_credentials, etc.) if needed:
The next lines create a DefaultOAuth2AuthorizedClientManager that uses:
ClientRegistrationRepositoryto look up client configurations (client-id, client-secret, scopes, etc.)OAuth2AuthorizedClientRepositoryto store/retrieve authorized clients (e.g., from the session or request context).
The final line configures the manager to use the custom provider, which supports token exchange.
π§ Purpose of the OAuth2AccessTokenResponseClient Bean
This tells Spring Security how to handle the token exchange request and response. The RestClientTokenExchangeTokenResponseClient is a built-in implementation that uses a REST client to perform the token exchange.
Extend the Rest API endpoint to perform the Token Exchange
The final step is to extend the existing API endpoint /api/messages to perform the token exchange with the authorization server and successfully call the target resource server with the exchanged token.
To achieve this, we need to change the ClientApi class to use the OAuth2AuthorizedClientManager to perform the token exchange and call the target resource server with the exchanged token.
π Breakdown of What this Method Does
π Accept secured requests
Accepts incoming requests with a JWT token
π Perform token exchange
Uses the incoming token to obtain a new access token
π Call downstream service
Calls another resource server with the new token
π¦ Aggregate response
Returns a message containing data from the target resource
It receives an authenticated user (JwtAuthenticationToken) representing a valid JWT-based access token that was used to call this resource server.
It creates an OAuth2AuthorizeRequest object that specifies the client registration ID (from application.yml) and the principal (the authenticated user). Finally, it triggers token exchange using the OAuth2AuthorizedClientManager and the jwtAuthentication token as the subject token.
Ensures the token exchange worked and an access token was received.
Now it uses the exchanged token and passes it as a bearer token to make a request to the target resource server.
Restart the Token Exchange Resource Server
Now that we have implemented the token exchange, we need to restart the token exchange resource server to apply the changes.
After it successfully has restarted, retry the complete flow by navigating to http://localhost:8080/client in your browser. This time the complete flow should work successfully, and you should see a message from the target resource server.
β Congratulations: You have implemented a complete OAuth2 Token Exchange flow using Spring Security and Spring Authorization Server. You have learned how to configure the authorization server, the client application, the token exchange resource server, and the target resource server. You have also learned how to perform the token exchange and call the target resource server with the exchanged token.
β That also completes the workshop! You have learned about three important features of Spring Security
Passkeys
Enhanced Authorization (i.e., authorize domain objects)
OAuth2 Token Exchange
If you have any questions or feedback, please feel free to reach out to me (just connect via LinkedIn). I hope you enjoyed the workshop and learned something new!
Last updated