Auth Exchange
Auth exchange lets an application that has already authenticated a user with your identity provider reach the Willow MCP gateway using that user's JWT. Willow verifies the JWT against your IdP's JWKS endpoint and acts as the matching Willow user. There is no browser sign-in, no OAuth redirect, and no token to store.
This is the right fit when your own product embeds an agent and already knows who the user is. It is not meant for desktop MCP clients such as Cursor or Claude Desktop, which should use the standard OAuth flow.
There are two ways to use it:
- Gateway headers — send the JWT on every MCP request and let the gateway run the exchange. Simplest, and the recommended default.
- The exchange API — call
POST /api/auth-exchangeyourself to get a Willow access token, then use that token as a normal Bearer credential.
Prerequisites
- SSO configured with Okta or Keycloak (see Configure SSO), with Enable Auth Exchange turned on and a JWKS URI set.
- An API token with the
connect:exchange-authscope, created in Admin → Settings → API Tokens (see API Tokens).connect:writeandallalso grant it. - Every user you exchange for must already exist in the organization. Auth exchange resolves an existing user by email; it does not create one. Use SCIM or SSO login to provision users first.
Gateway headers
Point your MCP client at the gateway as usual and add three headers to every request:
| Header | Value |
|---|---|
Authorization | Bearer <jwt> — the JWT issued by your IdP for the end user |
x-api-key | Your Willow API token (wxt_...) with the connect:exchange-auth scope |
x-auth-exchange | true |
x-auth-exchange is what tells the gateway that the Bearer value is an external JWT rather than a Willow access token. Without it the JWT is rejected as an invalid token.
{
"mcpServers": {
"willow": {
"url": "https://your-org.mcp-s.com/mcp",
"headers": {
"Authorization": "Bearer ${IDP_JWT}",
"x-api-key": "wxt_...",
"x-auth-exchange": "true"
}
}
}
}
On the first request the gateway verifies the JWT, exchanges it for Willow credentials, and caches the result for up to five minutes so that repeat calls with the same JWT skip the round trip. When your JWT rotates, send the new one and the exchange runs again — nothing else in your client needs to change.
Errors
| Status | Meaning |
|---|---|
| 401 | x-api-key is missing, or the JWT failed verification against your JWKS URI |
| 403 | The API token lacks the connect:exchange-auth scope, or no Willow user matches the JWT's identity |
| 400 | No JWKS URI is configured, or the JWT carries none of sub, email, client_id |
Failures come back as standard OAuth errors with a WWW-Authenticate header, so a spec-compliant MCP client surfaces the reason to the user.
Exchange API
Call the exchange endpoint directly when you would rather hold a Willow token yourself — for example to reuse one token across many requests, or to inspect its expiry.
curl -X POST https://your-org.mcp-s.com/api/auth-exchange \
-H "Authorization: Bearer ${IDP_JWT}" \
-H "x-api-key: wxt_..."
The response contains an access_token that you then send to the gateway as an ordinary Authorization: Bearer credential, with no x-api-key or x-auth-exchange header. See the Exchange Auth API reference for the full response shape.
Security notes
- The API token is an organization-wide credential. Keep it on your server and never ship it to a browser or end-user device.
- The JWT decides who the request acts as; the API token only authorizes your application to perform exchanges at all. Both are required.
- Tool permissions, toolkits, and audit logs all resolve against the Willow user the JWT maps to, exactly as they would after a browser sign-in.