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.
MisconfigurationPKCE verifier not checked
The authorization server advertises S256 and records the code challenge, but a token request can be shaped so the verifier is never compared with it. An authorization code that leaked, through a redirect, a log or a referrer, can then be exchanged by whoever has it, without the secret the honest client holds. The check that PKCE exists for is the one that is skipped. This is the pattern behind CVE-2025-4144.
- Defeats PKCE with S256 advertisedAuthorization serverListed servers under MCP Authorization 2026-07-28: 34 supported, 0 partial, 0 unsupported, 2 unknown, 3 not applicable.
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 10: Agent host to auth.tasks.examplereplaces "token-request"
Sent by whoever holds the code. The honest client's code_verifier is not needed, because the server will not ask for it.
4.6. Server Verifies code_verifier before Returning the TokensProof Key for Code Exchange by OAuth Public Clients (PKCE) rfc
Step 11: auth.tasks.example to Agent hostreplaces "token-response"
The token is as valid as the baseline one. Nothing downstream can tell that the code was redeemed by a party that never held the verifier.
Security Considerations › Authorization Code ProtectionMCP Authorization 2026-07-28
Access token issued without the PKCE checktyp 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 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