Delegation chain explorer
An MCP client obtains a token for an MCP server
The baseline chain of MCP Authorization 2026-07-28: an agent host discovers where a tasks server's authorization server is, identifies itself with a client ID metadata document, runs the OAuth 2.1 code flow with PKCE and a resource indicator, and presents the token the server was issued for. The server validates it and uses a token of its own for the API behind it.
AttackIssuer mix-up
The authorization response arrives without an iss parameter the client checks, so a response crafted by an attacker-controlled authorization server is taken for the real one and the client sends the authorization code, and its code verifier, to the attacker's token endpoint.
- Defeats Issuer identifier in authorization responsesAuthorization serverListed servers under MCP Authorization 2026-07-28: 9 supported, 0 partial, 22 unsupported, 3 unknown, 5 not applicable.
- Defeats Exact iss comparisonClientA client requirement; the atlas does not observe clients.
The chain, step by step
Step 1: Agent host to Tasks MCP server
The host has no token for this server yet, so it starts with the request any client makes first. Everything it learns about where to get a token comes from the answer.
Authorization Server Discovery › Protected Resource Metadata Discovery RequirementsMCP Authorization 2026-07-28
Step 2: Tasks MCP server to Agent host
The server must point at its protected resource metadata, either in this challenge or at the well-known location; this server does both.
Authorization Server Discovery › Protected Resource Metadata Discovery RequirementsMCP Authorization 2026-07-28
Step 3: Agent host to Tasks MCP server
3. Protected Resource MetadataOAuth 2.0 Protected Resource Metadata rfc
Step 4: Tasks MCP server to Agent host
The resource identifier is what the client will ask the token to be bound to; the authorization server list is where it will ask.
Authorization Server Discovery › Authorization Server LocationMCP Authorization 2026-07-28
Step 5: Agent host to auth.tasks.example
3. Obtaining Authorization Server MetadataOAuth 2.0 Authorization Server Metadata rfc
Step 6: auth.tasks.example to Agent host
The issuer must match the URL the client asked; the client keeps the metadata keyed by that issuer.
Authorization Server Discovery › Authorization Server Metadata DiscoveryMCP Authorization 2026-07-28
Step 8: auth.tasks.example to Alex
The authorization server fetches the document at the client_id URL, checks that the redirect URI is one it lists, and shows Alex who is asking.
Client Registration › Client ID Metadata DocumentsMCP Authorization 2026-07-28
Step 9: auth.tasks.example to Agent hostreplaces "authorization-response"
The client started flows with two authorization servers, one of them the attacker's. Without iss it cannot tell whose response this is and pairs the code with the wrong one.
2. Response Parameter issOAuth 2.0 Authorization Server Issuer Identification rfc
Step 10: Agent host to auth.tasks.examplereplaces "token-request"
The attacker redeems the code at the honest server and holds Alex's access token.
4.4. Mix-Up AttacksBest Current Practice for OAuth 2.0 Security rfc
Step 11: auth.tasks.example to Agent host
The authorization server verified the code verifier against the challenge and issued a token whose audience is the resource the client asked for.
Security Considerations › Token Audience Binding and ValidationMCP Authorization 2026-07-28
Access token for the Tasks MCP servertyp at+jwt · alg ES256 · kid auth-2026-1
- iss
- https://auth.tasks.example
- sub
- alex
- aud
- https://mcp.tasks.example/mcp
- client_id
- https://agent.example/client.json
- scope
- tasks:read tasks:write
- exp
- 1790000000
- iat
- 1789996400
- jti
- 7f2c
Unchanged since the previous token in this chain. Shown in the RFC 9068 JWT profile; an opaque token would carry the same binding on the server side.
Step 12: Agent host to Tasks MCP server
Authorization › Access Token UsageMCP Authorization 2026-07-28
Access token as presentedtyp at+jwt · alg ES256 · kid auth-2026-1
- iss
- https://auth.tasks.example
- sub
- alex
- aud
- https://mcp.tasks.example/mcp
- client_id
- https://agent.example/client.json
- scope
- tasks:read tasks:write
- exp
- 1790000000
- iat
- 1789996400
- jti
- 7f2c
Unchanged since the previous token in this chain.
Step 13: Tasks MCP server to itself
A token issued for another resource is rejected here, whoever presents it. This is the check the resource parameter exists for.
Security Considerations › Token Audience Binding and ValidationMCP Authorization 2026-07-28
Step 14: Tasks MCP server to Tasks API
The server never forwards the token it received. It holds credentials of its own for the API and obtains a token whose audience is the API, so the API can tell who is calling on whose behalf.
Security Considerations › Access Token Privilege RestrictionMCP Authorization 2026-07-28
The server's own token for the Tasks APItyp at+jwt · alg ES256 · kid auth-2026-1
- iss
- https://auth.tasks.example
- sub
- alex
- audchanged
- https://api.tasks.example
- client_idchanged
- tasks-mcp-server
- scopechanged
- tasks:read
- actadded
{ "sub": "tasks-mcp-server" }- expchanged
- 1789999000
- iatchanged
- 1789996500
- jtichanged
- 9b10
7 claims differ from the previous token in this chain.
Step 15: Tasks MCP server to Agent host
Authorization › Access Token UsageMCP Authorization 2026-07-28
Requirements this chain exercises
- resource_metadata in the 401 challengeMCP server
- PRM reachable at a well-known URIMCP server
- PRM lists an authorization serverMCP server
- Authorization server metadata discoverableAuthorization server
- Client ID Metadata Documents supportedAuthorization server
- PKCE on every authorization requestClient
- PKCE with S256 advertisedAuthorization server
- resource parameter on token requestsClient
- Resource indicators honouredAuthorization server
- Issuer identifier in authorization responsesAuthorization server
- Exact iss comparisonClient
- Bearer token only in the Authorization headerMCP server
- Audience validationMCP server
- No token passthrough to upstream APIsMCP server