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
Authorizationheader 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
localStorageinstead 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.