Click any words you think contain an error. Click again to unmark.
The token exchange skips PKCE verification, so an attacker who steals the authorization code can redeem it as the server, a classic confused-deputy escalation.
Imagine a coat-check desk that gives you a ticket when you drop off your coat. PKCE is like writing a secret word on your half of the ticket and keeping the matching half in your pocket. When you return, the attendant checks both halves agree before handing back the coat. This server skips that check. It gives the coat to whoever shows up with any ticket stub, even one snatched from the trash. Worse, the server fetches the coat using its own master key, which opens far more closets than yours ever should. So a thief with a stolen stub walks away wearing the server's privileges, not just your own.
Concept explanation~2 min read
Everything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example. Click to expand.
Concept explanation~2 min read
Everything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example. Click to expand.
This is a spot the bug question, and the bug is a single missing validation with outsized consequences. The server runs OAuth 2.1, generates an authorization URL, redirects the user to the identity provider, then exchanges the returned code for a token. The defect is the last clause: it exchanges the code without validating that the code_verifier matches the code_challenge from the initial request.
That omission is the entire vulnerability. PKCE is the mechanism that proves the party redeeming an authorization code is the same party that started the flow. Remove the check and possession of the code becomes sufficient to mint a token.
The reason this rises to a senior-level question is the second-order effect. In an MCP deployment the server is a privileged intermediary. When it redeems the code under its own identity and holds broad credentials, a stolen user code does not yield one user's access. It yields the server's. That is the confused-deputy pattern, and the rest of this walkthrough traces how the small omission produces the large blast radius, then lays out the secure pattern.
What PKCE proves and how the check works
PKCE, Proof Key for Code Exchange, binds the start of an OAuth flow to its end through a one-way hash. At the start, the client generates a high-entropy random secret, the code_verifier. It computes a code_challenge, normally the SHA-256 hash of the verifier, and sends only the challenge to the identity provider in the authorization request. The provider stores the challenge alongside the code it later issues.
When the client redeems the code at the token endpoint, it presents the raw code_verifier. The provider re-hashes that verifier and compares the result to the stored challenge. A match proves the redeemer holds the original secret. A mismatch, or an absent verifier, must be rejected.
The server in this question performs the redemption but skips the comparison. It accepts the code and returns a token to whoever presents the code, with no proof that they ever held the verifier. The cryptographic link between request and redemption is severed.
It is worth being precise about what PKCE does and does not protect. It does not encrypt the code, hide it from the network, or shorten its lifetime. It instead makes mere possession of the code insufficient. The redeemer must also prove knowledge of a secret that was never transmitted. That single property is what neutralizes the entire class of code interception attacks, and it is the property this implementation throws away.
Situations where this technique stops working.
2–4 min · Everything important, quickly.
| Aspect | Vulnerable code | Secure pattern |
|---|---|---|
| PKCE check | Verifier never validated | Verifier re-hashed and matched before token issue |
| Token model | One static token reused across users | Per-user token minted at consent |
| Audience binding | Token accepted by any backend | Token scoped to one intended audience |
| Blast radius | Server's full credential scope | Single consenting user's scope |
| Consent | Implicit and server-wide | Explicit, per scope per user |
Real products, models, and research that use this idea.
- The MCP authorization spec adopted OAuth 2.1 with mandatory PKCE in 2025, and reference servers like the GitHub and Sentry remote MCP servers verify the code_verifier server-side.
- The OWASP MCP Top 10 (2025) lists confused-deputy and token-passthrough abuse as distinct high-severity risks for remote MCP servers.
What an interviewer would ask next. Try answering before peeking at the approach.
QBeyond PKCE, what makes token passthrough such a dangerous anti-pattern for remote MCP servers?
Passthrough forwards an upstream token unchanged, so the downstream loses audience control and any caller inherits the token's full scope. Mint fresh per-audience tokens instead.
Red flags & common mistakes
The phrases that signal junior thinking. Click to expand.
Red flags & common mistakes
The phrases that signal junior thinking. Click to expand.
Thinking PKCE is only for public clients. OAuth 2.1 makes it mandatory for every client, including server-side MCP integrations that hold broad scopes.
60 second bullets to scan on the way to the call.
What the code_verifier and code_challenge each represent
Why OAuth 2.1 makes PKCE mandatory for all client types
Primary sources. Browse if you want the original framing.
Same topic, related formats. Practice these next.