LAB-019: Token Exchange and Delegated Access¶
Status¶
- Theory prerequisite:
docs/theory/token-exchange.md - Implementation:
oauth2-authmodule - Tests:
TokenExchangeLabTest,ClientCredentialsLabTest - Verification:
JAVA_HOME=/opt/homebrew/opt/openjdk@21/libexec/openjdk.jdk/Contents/Home ./gradlew :oauth2-auth:test
Measurable objective¶
Register an OAuth2 client for RFC 8693 token exchange, configure a TokenExchangeOAuth2AuthorizedClientProvider and a separate RestClient for delegated outbound calls, and verify that the client credentials and token-exchange managers are both wired without bean ambiguity.
Source artifact map¶
| File | Purpose |
|---|---|
OAuth2AuthConfig.java | Adds token-exchange-client to the ClientRegistrationRepository |
TokenExchangeConfig.java | TokenExchangeOAuth2AuthorizedClientProvider, manager, and delegationRestClient |
ClientCredentialsConfig.java | clientCredentialsAuthorizedClientManager and serviceClient |
ClientCredentialsLabTest.java | Existing LAB-014 tests, now uses @Qualifier to disambiguate managers |
TokenExchangeLabTest.java | Verifies the new token-exchange registration, manager, and RestClient |
Exercises¶
- Review
OAuth2AuthConfigand locate thetoken-exchange-clientregistration. - Inspect
TokenExchangeConfigand list the beans it contributes. - Explain why
@Qualifieris necessary for bothRestClientandOAuth2AuthorizedClientManagerbeans. - Identify the parameters that are still missing for an end-to-end token exchange (audience, requested token type, subject token source).
Commands¶
JAVA_HOME=/opt/homebrew/opt/openjdk@21/libexec/openjdk.jdk/Contents/Home ./gradlew :oauth2-auth:test
Positive and negative test expectations¶
| Scenario | Expected |
|---|---|
token-exchange-client registered | AuthorizationGrantType.TOKEN_EXCHANGE, token URI under the local Keycloak issuer, scope spring-security-reference-api |
tokenExchangeAuthorizedClientManager | Not null, distinct from the client-credentials manager |
delegationRestClient | Not null, wired to the token-exchange manager via OAuth2ClientHttpRequestInterceptor |
| Existing client-credentials tests | Still pass with the new beans present |
Production extension¶
- Add a custom
TokenExchangeGrantRequestEntityConverterto include the downstreamaudienceandrequested_token_type. - Implement a
subjectTokenResolverthat extracts the current user's access token from theSecurityContext. - Add an end-to-end test that runs against the local IdP and verifies the exchanged token audience.
- Use separate
client_idandclient_secretvalues for the token-exchange client.
Completion evidence¶
./gradlew :oauth2-auth:test
BUILD SUCCESSFUL
TokenExchangeLabTest: 3 passed
OidcAuthoritiesMapperTest: 3 passed
OAuth2LoginConfigurationTest: 4 passed
ClientCredentialsLabTest: 2 passed
Next lab¶
LAB-020 — Backend-for-Frontend (BFF) Token Handling.