All posts
MCP education··5 min read

OAuth for MCP servers: the 2025-06 spec, explained

Any MCP server that ships to real users needs per-user authorization, not a shared API key. The 2025-06 MCP spec formalizes OAuth 2.1 with PKCE as the path for remote HTTP servers: discovery via the well-known endpoint, dynamic client registration, bearer tokens on every request. The mechanics are well-trodden — what trips teams up is scope design, token storage, and revocation hygiene.

⌘
Command+K team
Platform engineering

Why OAuth, not API keys

An MCP server that ships to real users is multi-tenant by definition. Each tool call must run with the calling user's identity so audit logs, rate limits, and downstream API quotas attribute correctly. Shared API keys collapse that boundary and make every incident a forensic nightmare.

What the 2025-06 spec says

  • Remote HTTP MCP servers SHOULD implement OAuth 2.1 with PKCE.
  • Discovery via /.well-known/oauth-authorization-server.
  • Dynamic Client Registration (RFC 7591) so hosts can self-enroll.
  • Bearer tokens carried in the Authorization header on every request.

The end-to-end flow

  • Host (Claude Desktop, your widget) discovers the auth server.
  • Host opens a browser to the consent screen with a PKCE challenge.
  • User approves; auth server returns a code; host exchanges it for a token.
  • Host calls MCP tools with Authorization: Bearer ….
  • Gateway verifies the token and injects user identity into the tool context.

Common pitfalls

  • Storing access tokens in localStorage instead of memory + httpOnly refresh.
  • One giant scope ("full_access") — consent fatigue and unreviewable audit logs.
  • Skipping token revocation on workspace removal; tokens outlive the relationship.
  • Hand-rolling the OAuth server. Use a library or a gateway.

In Command+K

OAuth is built in. You declare tools and scopes; the gateway handles discovery, PKCE, token storage, refresh, and per-user injection. See Build MCP → Auth.

FAQ

Why does MCP need OAuth at all?
MCP servers expose tools that read and write real user data — issues, repos, calendars, payments. You need per-user authorization, not a shared API key. OAuth 2.1 with PKCE is the spec-recommended mechanism, and the MCP 2025-06 spec formalizes it as the auth path for remote HTTP servers.
Can I keep using API keys for early prototypes?
Yes — stdio servers running locally typically use the user's existing CLI credentials. The moment you ship a hosted HTTP MCP server that multiple users hit, you need OAuth (or a signed bearer token minted by your own auth system) so each request runs as the right principal.
Do I need to implement an OAuth server myself?
No. Front your MCP server with an OAuth-aware gateway that handles discovery, PKCE, token exchange, refresh, and revocation. Your tools just read the verified user identity from the request context.
What scopes should an MCP server request?
One scope per tool family, named after the action. Prefer least privilege — issues:read separate from issues:write — so a compromised token blast-radius is small and consent screens are legible.

Keep reading

Go deeper