C.W.K.
Stream
Lesson 01 of 05 · published

OAuth 2.1 — The Authorization Framework

~26 min · oauth, resource-server, scopes, tokens

Level 0Curious Reader
0 XP0/48 lessons0/14 achievements
0/100 XP to next level100 XP to go0% complete

For HTTP-transport MCP servers, authorization uses OAuth 2.1. The spec models the MCP server as an OAuth 2.1 Resource Server: it accepts access tokens, validates them, and uses the token's scopes to authorize each tool call. The MCP client is an OAuth client that obtains tokens from an external Authorization Server. Crucially, the MCP server is not in the auth-issuance business — it consumes tokens; it does not mint them.

The flow during a typical session: the host (running the MCP client) directs the user through an OAuth flow with the authorization server, gets back an access token (and refresh token), stores them, and includes the access token as a Bearer header on every MCP request. The MCP server validates the token (introspection or JWT verification), reads its scopes, and authorizes the request. Token refresh is the host's responsibility; the MCP server only sees Bearer tokens already minted.

Two specific MCP wrinkles worth knowing:

  1. Authorization Server discovery. The MCP server publishes a WWW-Authenticate header pointing at its authorization metadata when called without (or with an invalid) token. The client fetches the metadata, learns the issuer, scopes, and PKCE requirements, then runs the OAuth flow. This makes MCP servers self-describing for auth, the way OpenID Connect did for general identity.
  2. Client ID Metadata Documents (CIMD) — added in the 2025-11-25 revision. Instead of every MCP server requiring per-server client registration, a client publishes a metadata document at a well-known URL; servers fetch the document on demand. This is how MCP at scale avoids the "register your client with every service" friction that would otherwise kill adoption.

Code

Bearer-token request to an MCP server·text
POST /mcp HTTP/1.1
Authorization: Bearer eyJhbGciOiJSUzI1NiIs...
Content-Type: application/json

{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{...}}
WWW-Authenticate discovery on a missing token·text
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer resource_metadata="https://api.example.com/.well-known/oauth-protected-resource"

# Client follows the URL to learn issuer, scopes, PKCE requirements,
# and runs the OAuth 2.1 authorization-code flow before retrying.
Validating the token in your server (FastMCP / FastAPI style)·python
from fastapi import HTTPException, Depends
from authlib.integrations.starlette_client import OAuth

async def require_scope(scope: str, token: str = Depends(extract_bearer)):
    claims = verify_jwt(token, jwks=AUTH_SERVER_JWKS, audience="https://api.example.com")
    if scope not in claims.get("scope", "").split():
        raise HTTPException(403, "insufficient scope")
    return claims

External links

Exercise

Read the MCP authorization spec end to end. Then map each requirement to one of three buckets: 'my client must do this', 'my server must do this', 'the auth server must do this'. The mapping reveals which parts of OAuth you actually own and which you can delegate to existing infrastructure.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.