Agentgateway adds token exchange, jwt-assertion, and Entra OBO – agentgateway | Agent Connectivity SolvedSkip to contentagentgateway has joined the Agentic AI Foundation — Learn more
Docs<br>Standalone<br>Kubernetes<br>Models<br>Blog<br>Enterprise<br>Community
@agentgatewayGet Started<br>GitHub
Agentgateway adds token exchange, jwt-assertion, and Entra OBO<br>Native backend auth for RFC 8693 token exchange, RFC 7523 JWT bearer (jwt-assertion), and Microsoft Entra on-behalf-of — so agents can call downstream APIs as the user without hand-rolled ext_proc or custom agent code<br>Christian Posta<br>Jul 12, 2026<br>5 min read
← Back to blogShielding AI agents from sensitive MCP / API credentials (secrets, API keys, tokens, etc) is the prevailing best practice pattern to keep sensitive secrets from leaking into AI model conversations or across AI agent boundaries. OpenClaw, for example, has direct file system access in its most general deployment and can read files/secrets/env variables, etc and could easily send these secrets in any requests.<br>The right way in an enterprise environment: user identity + agent identity tied to an authorization grant, which determines what is allowed to be done. Any calls to MCP servers or APIs have their credentials injected transparently by the infrastructure. The cornerstone of this injection is exchanging an agent or user’s identity for the correct secrets/API keys/tokens.<br>In the upcoming agentgateway release, we have opensourced two new exchange capabilities, including a bonus third exchange opportunity with Microsoft Entra — all under backendAuth.oauthTokenExchange:<br>GrantSpecSubject sent asTypical IdPToken exchangeRFC 8693subject_tokenKeycloak, Okta, ZITADEL, Auth0, …JWT bearer (jwt-assertion)RFC 7523assertionKeycloak JWT Authorization Grant, many ASEntra on-behalf-of (OBO)Entra’s OBO (jwt-bearer + extras)assertionMicrosoft Entra ID<br>Entra is the important enterprise wrinkle: it does not speak RFC 8693 . Its OBO flow is jwt-bearer with requested_token_use=on_behalf_of. Same outcome (user-scoped downstream token), different grant shape — so both grants live under one oauthTokenExchange block.<br>RFC 8693 token exchange
Default grant. The gateway POSTs the inbound bearer as subject_token to your IdP’s token endpoint and attaches the returned access token upstream.<br>backendAuth:<br>oauthTokenExchange:<br>host: idp.example.com:443<br>tokenEndpointPath: /oauth2/default/v1/token<br>clientAuth:<br>clientId: gateway-client<br>clientSecret: $OAUTH_CLIENT_SECRET<br>method: clientSecretBasic<br>audiences:<br>- upstream-api<br>scopes:<br>- read
What the gateway sends (conceptually):<br>grant_type=urn:ietf:params:oauth:grant-type:token-exchange<br>subject_token=<br>subject_token_type=urn:ietf:params:oauth:token-type:access_token<br>audience=upstream-api<br>scope=read
Optional knobs that matter in agentic setups:<br>actorToken — RFC 8693 delegation (act claim). Useful when an agent identity is acting for a user.<br>resources — RFC 8707 resource indicators when the AS expects them (common for MCP / API audiences).<br>subjectToken.source — read the subject from a non-default header, cookie, or CEL expression instead of Authorization.<br>cache — in-memory cache keyed by subject + grant params; TTL capped by the subject JWT exp.<br>Runnable example: examples/traffic-token-exchange/oauth-rfc8693.<br>JWT assertion (RFC 7523 jwt-bearer)
Flip grantType: jwtBearer and the same policy speaks JWT bearer instead of token exchange. The inbound credential becomes the assertion (not subject_token). requestedTokenType / actorToken are rejected for this grant — they belong to RFC 8693.<br>backendAuth:<br>oauthTokenExchange:<br>host: idp.example.com:443<br>tokenEndpointPath: /realms/backend-oauth/protocol/openid-connect/token<br>grantType: jwtBearer<br>clientAuth:<br>clientId: requester-client<br>clientSecret: requester-secret<br>method: clientSecretBasic<br>audiences:<br>- target-client
Form shape:<br>grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer<br>assertion=<br>audience=target-client
This grant works for any authorization servers that support JWT Assertion Grant (RFC 7523). This is the grant Keycloak’s JWT Authorization Grant (preview in 26.5+) implements across realms — present a JWT from realm A, get a token from realm B that trusts A. Full two-realm walkthrough: examples/traffic-token-exchange/jwt-authz-grant.<br>Microsoft Entra OBO
Entra OBO is jwt-bearer with provider-specific extras. The hand-written request looks like:<br>curl -X POST "https://login.microsoftonline.com//oauth2/v2.0/token" \<br>-H "Content-Type: application/x-www-form-urlencoded" \<br>-d "client_id=" \<br>-d "client_secret=" \<br>-d "grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer" \<br>-d "requested_token_use=on_behalf_of" \<br>-d "scope=https://graph.microsoft.com/.default" \<br>-d "assertion="
Agentgateway produces that same request from config:<br>backendAuth:<br>oauthTokenExchange:<br>host: login.microsoftonline.com:443<br>tokenEndpointPath: //oauth2/v2.0/token<br>grantType: jwtBearer<br>clientAuth:<br>clientId:<br>clientSecret:<br>method: clientSecretPost # credentials in...