The OAuth flow for remote servers
Only remote HTTP servers use OAuth. The MCP server is an OAuth resource server, and the client discovers everything it needs, starting from a single 401.
By the end of this lesson you can
- follow the discovery chain from a 401 to the authorization server;
- explain what PKCE, the resource parameter and the iss check each prevent;
- say how a client gets an identity: pre-registration, metadata document or DCR;
- explain audience checks, the ban on token passthrough, and step-up with 403.
From one 401 to a token
The client needs no configuration beyond the server's URL. Each answer points to the next document.
The discovery chain
- The client simply tries:
POST /mcpwith no token. - The server answers
401. ItsWWW-Authenticateheader points at its metadata document and suggests minimal scopes. - The client fetches Protected Resource Metadata (RFC 9728). It names the authorization server that issues tokens for this resource. Mandatory for MCP servers.
- The client fetches the authorization server's metadata (RFC 8414, or OpenID configuration) and records its issuer and endpoints.
- It opens the browser at the authorize endpoint with a PKCE challenge and the
resourceparameter naming this MCP server. The user signs in and consents. - The code comes back; the client swaps it, with its PKCE verifier, for an access token whose audience is this one server.
- From now on, every request carries
Authorization: Bearer …, and the server validates it every time.
Step through the whole flow
Four lanes: the browser, the MCP client, the MCP server and the authorization server. Every step shows the real HTTP request or document.
What PKCE buys you
The authorization code travels through the browser, where other software might see it. PKCE makes a stolen code useless.
A secret only the real client knows
- Before anything else, the client invents a random verifier and computes its SHA-256 hash, the challenge.
- The authorization request carries only the challenge (
code_challenge_method=S256). The authorization server stores it. - The authorization code comes back through the browser redirect, where other software may see it.
- An attacker who copied the code tries to redeem it, but has no verifier. Refused.
- The real client sends the code with the verifier; the server hashes it, matches the challenge, and issues the token.
One token, one audience
The resource parameter (RFC 8707) goes on both the authorization and the token request, so the token is minted for this one server. The server enforces the other half.
Audience and passthrough
- The token's audience is server A. A validates it on every request and accepts it.
- The same token presented to server B is refused: it was not issued for B. This stops a token leaked to one server being used at another.
- Server A needs to call GitHub. Forwarding the user's token would be token passthrough, which the spec forbids.
- Instead A uses its own credential for GitHub, a separate token with its own audience and scopes.
The rules in one place
Spec rules
- Protected Resource Metadata (RFC 9728) is mandatory: it is how the client finds the authorization server.
- Clients support both AS discovery documents (RFC 8414 and OpenID configuration) and record the issuer.
- Clients SHOULD use the scope in the 401 challenge first, then
scopes_supported. - The resource parameter (RFC 8707) MUST be sent on both the authorization and token requests.
- When the redirect carries
iss, the client MUST check it against the recorded issuer (RFC 9207) to stop mix-up attacks; if the authorization server advertisesisssupport, a redirect without it is rejected. - Client registration, in order of preference (SHOULD): pre-registered details if the client already has them, then a Client ID Metadata Document (the client id is a URL the authorization server fetches), then Dynamic Client Registration as a deprecated fallback, then asking the user.
- Servers MUST validate the token's audience on every request and MUST NOT accept or pass through tokens issued for anything else.
- A
403withinsufficient_scopestarts a step-up: the client re-authorizes asking for the union of its old and the new scopes.
Key idea
The bearer token on every request is also how a stateless replica knows who you are. No session, no sticky routing: identity arrives with each request (lesson 11).
Quick check
The client knows only https://mcp.example.com/mcp. How does it find the authorization server?
WWW-Authenticate header's resource_metadata points to the RFC 9728 document, whose authorization_servers names the issuer.What does the resource parameter achieve?
Mid-session the server answers 403 with insufficient_scope. What should the client do?
Your MCP server needs to call the GitHub API on the user's behalf. Can it forward the bearer token it received?
Recap
- 401 → Protected Resource Metadata (RFC 9728) → AS metadata → authorize with PKCE and
resource→ code withiss→ token → Bearer on every request. - Client identity: pre-registration if it exists, else Client ID Metadata Document, else DCR (deprecated).
- PKCE makes a stolen code useless;
issstops mix-ups;resourcesets the audience. - Servers check audience every time, never pass tokens through, and use 403
insufficient_scopefor step-up.