OAuth 2.0 Token Exchange Authentication
This feature is currently in early access.
The OAuth 2.0 Token Exchange middleware lets Hub API Gateway exchange an incoming subject token for a new access token scoped to a downstream service, following RFC 8693. It also supports Microsoft Entra ID's On-Behalf-Of flow, which uses a dedicated grant type instead of the RFC 8693 grant.
Every application brings its subject token to Hub API Gateway using one of the following sources:
- A header (with a scheme if the token is provided using the
Authorizationheader, the default), - A query parameter,
- A cookie.
Hub API Gateway then calls the authorization server to exchange the subject token for a new access token, and forwards the request upstream with the exchanged token in the Authorization header.
RFC 8693 Token Exchange
In this mode, Hub API Gateway exchanges the subject token by sending the RFC 8693
urn:ietf:params:oauth:grant-type:token-exchange grant to the authorization server, as described in the diagram below.
To exchange a JWT subject token read from the Authorization header for a new access token, apply the following configuration after adjusting it to your needs:
- Middleware RFC 8693 Token Exchange
- Kubernetes Secret
- IngressRoute
---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: oauth-token-exchange
namespace: apps
spec:
plugin:
oAuthTokenExchange:
method: rfc8693
url: https://tenant.auth0.com/oauth/token
clientID: "urn:k8s:secret:oauth-client:client_id"
clientSecret: "urn:k8s:secret:oauth-client:client_secret"
rfc8693:
subjectTokenType: "urn:ietf:params:oauth:token-type:jwt"
requestedTokenType: "urn:ietf:params:oauth:token-type:access_token"
audience: https://api.example.com
apiVersion: v1
kind: Secret
metadata:
name: oauth-client
namespace: apps
stringData:
client_id: my-oauth-client-id
client_secret: my-oauth-client-secret
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: secure-applications-apigateway-oauth-token-exchange
namespace: apps
spec:
entryPoints:
- websecure
routes:
- match: Path(`/my-app`)
kind: Rule
services:
- name: whoami
port: 80
middlewares:
- name: oauth-token-exchange
Keycloak requires rfc8693.subjectTokenType: "urn:ietf:params:oauth:token-type:access_token". Use this value instead of jwt when the authorization server is Keycloak.
Advanced options are described in the reference page.
For example, you can find how to add a cache layer using a Redis store so Hub API Gateway does not exchange the same subject token on every request.
Pinning the client authentication method
By default, Hub API Gateway auto-detects whether the authorization server expects client credentials in an HTTP Basic header or in the request body, and reuses that detection for the exchange. If the authorization server rejects HTTP Basic, this detection adds one extra request to the authorization server on every token exchange.
Set rfc8693.clientAuthMethod to skip detection and send credentials the right way on the
first try:
in_header— send credentials using HTTP Basic authentication.in_params— send credentials in the request body.
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: oauth-token-exchange
namespace: apps
spec:
plugin:
oAuthTokenExchange:
method: rfc8693
url: https://tenant.auth0.com/oauth/token
clientID: "urn:k8s:secret:oauth-client:client_id"
clientSecret: "urn:k8s:secret:oauth-client:client_secret"
rfc8693:
subjectTokenType: "urn:ietf:params:oauth:token-type:jwt"
requestedTokenType: "urn:ietf:params:oauth:token-type:access_token"
audience: https://api.example.com
clientAuthMethod: in_params
Auto-detection (the default) tries HTTP Basic first and falls back to the request body if
the authorization server rejects it. Pinning rfc8693.clientAuthMethod removes that
fallback along with the extra request. If you pin the wrong method for your authorization
server, every exchange fails instead of falling back. Confirm which style your
authorization server expects before pinning it in production.
Microsoft Entra ID On-Behalf-Of
Microsoft Entra ID diverges from RFC 8693 with its own On-Behalf-Of grant.
Set method: entraID to use it. Entra ID requires client authentication, either with a client secret or with a client certificate.
Using a client secret
- Middleware Entra ID with client secret
- Kubernetes Secret
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: oauth-token-exchange-entraid
namespace: apps
spec:
plugin:
oAuthTokenExchange:
method: entraID
url: https://login.microsoftonline.com/YOUR-TENANT-ID/oauth2/v2.0/token
clientID: "urn:k8s:secret:oauth-client:client_id"
clientSecret: "urn:k8s:secret:oauth-client:client_secret"
entraID:
scopes:
- api://downstream-app/.default
apiVersion: v1
kind: Secret
metadata:
name: oauth-client
namespace: apps
stringData:
client_id: my-entraid-client-id
client_secret: my-entraid-client-secret
Using a client certificate
Instead of a client secret, Entra ID can authenticate the client with a signed JWT assertion built from an RSA certificate and private key:
- Middleware Entra ID with client certificate
- Kubernetes Secret
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: oauth-token-exchange-entraid-cert
namespace: apps
spec:
plugin:
oAuthTokenExchange:
method: entraID
url: https://login.microsoftonline.com/YOUR-TENANT-ID/oauth2/v2.0/token
clientID: "urn:k8s:secret:oauth-client:client_id"
entraID:
scopes:
- api://downstream-app/.default
clientCertificate:
certificate: "urn:k8s:secret:oauth-client-cert:certificate"
privateKey: "urn:k8s:secret:oauth-client-cert:privateKey"
apiVersion: v1
kind: Secret
metadata:
name: oauth-client-cert
namespace: apps
stringData:
certificate: |-
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
privateKey: |-
-----BEGIN PRIVATE KEY-----
...
-----END PRIVATE KEY-----
Microsoft Entra ID only accepts RSA certificate credentials signed with PS256. PKCS1 and PKCS8 RSA private keys are supported; other key types are rejected.
Related Content
- See the full options in the dedicated section.
- See how to secure your API using OAuth2 Client Credentials.
- See how to secure your API using OAuth2 Token Introspection.
