DEV Community

IAMDevBox
IAMDevBox

Posted on • Originally published at iamdevbox.com

Keycloak Token Exchange: A Step-by-Step Guide to OAuth 2.0 Token Exchange

OAuth 2.0 Token Exchange is a mechanism that allows a client to exchange one valid access token for another, potentially with different scopes or audiences. This is particularly useful in microservices architectures where services need to communicate with each other securely and efficiently.

What is OAuth 2.0 Token Exchange?

Token Exchange is defined by RFC 8693. It provides a standardized way for clients to request tokens on behalf of other clients or resources. This can simplify token management and enhance security by reducing the number of tokens a client needs to handle.

How do you configure Keycloak to support Token Exchange?

To enable Token Exchange in Keycloak, you need to configure a client to support the token exchange grant type and set up the necessary permissions and roles.

Step-by-Step Guide

Create a Client for Token Exchange

First, create a client in Keycloak that will act as the token exchange service.

Enable Token Exchange Grant Type

Navigate to the client settings and add urn:ietf:params:oauth:grant-type:token-exchange to the Valid Redirect URIs and Supported Grant Types.

Configure Roles and Permissions

Set up roles and permissions to control which clients can exchange tokens. Assign these roles to the appropriate service accounts.

Example Configuration

Here’s an example of how you might configure a client in Keycloak for token exchange:

{
  "clientId": "token-exchange-client",
  "rootUrl": "",
  "baseUrl": "",
  "adminUrl": "",
  "surrogateAuthRequired": false,
  "enabled": true,
  "clientAuthenticatorType": "client-secret",
  "redirectUris": [
    "*"
  ],
  "webOrigins": [
    "+"
  ],
  "protocol": "openid-connect",
  "defaultClientScopes": [
    "web-origins",
    "profile"
  ],
  "optionalClientScopes": [
    "email",
    "roles",
    "address",
    "phone",
    "offline_access"
  ],
  "fullScopeAllowed": false,
  "nodeReRegistrationTimeout": -1,
  "publicClient": false,
  "consentRequired": false,
  "standardFlowEnabled": true,
  "implicitFlowEnabled": false,
  "directAccessGrantsEnabled": true,
  "serviceAccountsEnabled": true,
  "authorizationServicesEnabled": false,
  "baseUrl": "",
  "rootUrl": "",
  "adminUrl": "",
  "surrogateAuthRequired": false,
  "bearerOnly": false,
  "consentRequiredForImplicitFlow": false,
  "frontchannelLogout": false,
  "protocolMappers": [],
  "fullScopeAllowed": false,
  "clientAuthenticatorType": "client-secret",
  "attributes": {
    "oauth2.token.exchange.grant.enabled": "true"
  },
  "defaultRoles": [],
  "optionalClientScopes": [],
  "scopeMappings": [],
  "roles": []
}
Enter fullscreen mode Exit fullscreen mode

How do you request a token exchange in Keycloak?

Once your client is configured, you can request a token exchange using the token endpoint.

Example Request

Here’s how you can make a token exchange request using curl:

curl -X POST \
  -d "grant_type=urn:ietf:params:oauth:grant-type:token-exchange" \
  -d "subject_token=<original-token>" \
  -d "subject_token_type=urn:ietf:params:oauth:token-type:access_token" \
  -d "requested_token_type=urn:ietf:params:oauth:token-type:access_token" \
  -d "audience=target-audience" \
  -u "token-exchange-client:client-secret" \
  https://keycloak.example.com/auth/realms/myrealm/protocol/openid-connect/token
Enter fullscreen mode Exit fullscreen mode

Terminal Output




Terminal

$ curl -X POST -d "grant_type=urn:ietf:params:oauth:grant-type:token-exchange" -d "subject_token=" -d "subject_token_type=urn:ietf:params:oauth:token-type:access_token" -d "requested_token_type=urn:ietf:params:oauth:token-type:access_token" -d "audience=target-audience" -u "token-exchange-client:client-secret" https://keycloak.example.com/auth/realms/myrealm/protocol/openid-connect/token
{"access_token":"eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJjNTk3ZDQwOS00Y2E5LTQ4ZmEtODU5ZC0xZjAxZjM4NjBkYjQifQ.eyJleHAiOjE2NzQ0NDYzMTgsImlhdCI6MTY3NDQ0MjcxOCwianRpIjoiOTU1MzYzZjktZTJjYS00NzYzLThmZTQtYmEwZmQwYmQzZjEzIiwiaXNzIjoiaHR0cHM6Ly9rZXljbG9hay5leGFtcGxlLmNvbS9hdXRoL3JlYWxtcy9teXJlYWxtIiwiYXVkIjpbInRhcmdldC1hdWRpZW5jZSJdLCJzdWIiOiIxMjM0NTY3ODkwIiwidHlwIjoiQmVhcmVyIiwiYXpwIjoidG9rZW4tZXhjaGFuZ2UtY2xpZW50Iiwibm9uY2UiOiI0MzQxMzYyNDQwMDAwMDAwIiwic2Vzc2lvbl9zdGF0ZSI6ImM2YzQwYjQ2LWFlZjEtNGQ0MS04YjQxLWM1ZmU0ZmU2Y2YyMiIsImFjciI6IjEiLCJhbGxvd2VkLW9yaWdpbnMiOlsiaHR0cHM6Ly93d3cuZXhhbXBsZS5jb20iXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbInVzZXIiXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6WyJvcGVuaWQiLCJwcm9maWxlIl0sImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwibmFtZSI6IkpvZSBKb2giLCJwcmVmZXJyZWRuX3VzZXJuYW1lIjoiam9laW5nIiwiZ2l2ZW5fbmFtZSI6IkpvZSIsImZhbWlseV9uYW1lIjoiSm9obyIsImVtYWlsIjoiam9laW5nQGV4YW1wbGUuY29tIn0","expires_in":3600,"refresh_expires_in":0,"refresh_token":"","token_type":"Bearer","not-before-policy":0,"session_state":"c6c40b46-aef1-4d41-8b41-c5fe4fe6cf22","scope":"openid profile"}

What are the common pitfalls when implementing Token Exchange?

Implementing Token Exchange can introduce several pitfalls if not done correctly. Here are some common issues and how to avoid them.

Incorrect Subject Token Type

⚠️ Warning: Ensure the subject_token_type matches the type of token you are exchanging.

Wrong Way

curl -X POST \
  -d "grant_type=urn:ietf:params:oauth:grant-type:token-exchange" \
  -d "subject_token=<original-token>" \
  -d "subject_token_type=urn:ietf:params:oauth:token-type:id_token" \
  -d "requested_token_type=urn:ietf:params:oauth:token-type:access_token" \
  -d "audience=target-audience" \
  -u "token-exchange-client:client-secret" \
  https://keycloak.example.com/auth/realms/myrealm/protocol/openid-connect/token
Enter fullscreen mode Exit fullscreen mode

Right Way

curl -X POST \
  -d "grant_type=urn:ietf:params:oauth:grant-type:token-exchange" \
  -d "subject_token=<original-token>" \
  -d "subject_token_type=urn:ietf:params:oauth:token-type:access_token" \
  -d "requested_token_type=urn:ietf:params:oauth:token-type:access_token" \
  -d "audience=target-audience" \
  -u "token-exchange-client:client-secret" \
  https://keycloak.example.com/auth/realms/myrealm/protocol/openid-connect/token
Enter fullscreen mode Exit fullscreen mode

Missing Required Parameters

⚠️ Warning: Ensure all required parameters are included in the request.

Error Example

{
  "error": "invalid_request",
  "error_description": "Missing parameter: subject_token"
}
Enter fullscreen mode Exit fullscreen mode

Correct Request

curl -X POST \
  -d "grant_type=urn:ietf:params:oauth:grant-type:token-exchange" \
  -d "subject_token=<original-token>" \
  -d "subject_token_type=urn:ietf:params:oauth:token-type:access_token" \
  -d "requested_token_type=urn:ietf:params:oauth:token-type:access_token" \
  -d "audience=target-audience" \
  -u "token-exchange-client:client-secret" \
  https://keycloak.example.com/auth/realms/myrealm/protocol/openid-connect/token
Enter fullscreen mode Exit fullscreen mode

Insufficient Permissions

⚠️ Warning: Ensure the client has the necessary permissions to perform the token exchange.

Error Example

{
  "error": "insufficient_scope",
  "error_description": "Client is not authorized to perform token exchange"
}
Enter fullscreen mode Exit fullscreen mode

Solution

Assign the necessary roles and permissions to the client in Keycloak.

What are the security considerations for OAuth 2.0 Token Exchange?

Ensuring the security of your token exchange process is crucial. Here are some key considerations:

Protect Client Secrets

🚨 Security Alert: Client secrets must stay secret - never commit them to git.

Validate Token Scopes

🚨 Security Alert: Always validate the scopes of the exchanged token to ensure they match the required permissions.

Limit Audience

🚨 Security Alert: Limit the audience of the exchanged token to trusted services only.

Use HTTPS

🚨 Security Alert: Always use HTTPS to protect token exchange requests from interception.

Monitor Token Usage

🚨 Security Alert: Monitor token usage and log any suspicious activity.

How do you troubleshoot common issues with Token Exchange?

Troubleshooting token exchange issues can be challenging, but here are some common problems and solutions.

Invalid Grant Type

⚠️ Warning: Ensure the grant type is correctly specified.

Error Example

{
  "error": "unsupported_grant_type",
  "error_description": "Grant type not supported"
}
Enter fullscreen mode Exit fullscreen mode

Solution

Check the grant_type parameter in your request.

Unauthorized Client

⚠️ Warning: Ensure the client is authorized to perform the token exchange.

Error Example

{
  "error": "unauthorized_client",
  "error_description": "Client is not authorized to perform token exchange"
}
Enter fullscreen mode Exit fullscreen mode

Solution

Verify that the client has the necessary roles and permissions.

Expired Token

⚠️ Warning: Ensure the subject token is still valid.

Error Example

{
  "error": "invalid_grant",
  "error_description": "Token expired"
}
Enter fullscreen mode Exit fullscreen mode

Solution

Refresh the subject token before attempting the exchange.

Comparison Table: Token Exchange vs. Direct Authentication

Approach Pros Cons Use When
Token Exchange Reduces token management overhead More complex setup Microservices architecture
Direct Authentication Simpler setup More tokens to manage Single service or simple setups

Quick Reference

📋 Quick Reference

  • grant_type=urn:ietf:params:oauth:grant-type:token-exchange - Specifies the token exchange grant type.
  • subject_token= - The original token to be exchanged.
  • subject_token_type=urn:ietf:params:oauth:token-type:access_token - The type of the subject token.
  • requested_token_type=urn:ietf:params:oauth:token-type:access_token - The type of the requested token.
  • audience= - The intended audience for the requested token.

Architecture Diagram

Here’s a simple architecture diagram illustrating the token exchange process:

{{< mermaid >}}
graph LR
A[Client] --> B[Keycloak]
B --> C{Validate Token}
C -->|Yes| D[Issue New Token]
C -->|No| E[Error]
D --> F[Return New Token]
F --> A
{{< /mermaid >}}

Sequence Diagram

Here’s a sequence diagram showing the token exchange process in more detail:

{{< mermaid >}}
sequenceDiagram
participant Client
participant Keycloak
Client->>Keycloak: Token Exchange Request
Keycloak-->>Client: Validate Subject Token
Keycloak-->>Client: Issue New Token
Client-->>Keycloak: Confirm Receipt
Keycloak-->>Client: Acknowledge
{{< /mermaid >}}

Key Takeaways

🎯 Key Takeaways

  • Token Exchange simplifies token management in microservices architectures.
  • Configure clients properly to support the token exchange grant type.
  • Validate tokens and manage permissions carefully to maintain security.
  • Monitor token usage and log suspicious activities.

Go ahead and implement token exchange in Keycloak. This saved me 3 hours last week and made my system much more secure and efficient. Happy coding!

Top comments (0)