Security8 min read

OAuth 2.1 for MCP: What the Spec Standardised and What You Need to Know

The 2025-06-18 Model Context Protocol specification standardised on OAuth 2.1 with PKCE for every remote MCP server. The change cleans up a previously fragmented auth landscape and adds explicit guidance against confused-deputy attacks. Here is the practical guide to what changed, what your client has to implement, and what your server needs to expose.

Before the spec: every server, its own auth

Remote MCP servers before mid-2025 each defined their own auth. Some used static API keys passed in headers. Some used custom JWT flows. A few implemented OAuth 2.0 — and each of those used a different combination of flows, scopes, and token formats. MCP client authors had to implement an "auth model adapter" per server, which scaled poorly and made remote MCPs harder to ship than local stdio servers.

The 2025-06-18 spec replaced that mess with one rule: remote MCP servers MUST support OAuth 2.1 with PKCE for user-facing flows, and SHOULD support dynamic client registration. Clients now implement one flow and it works against every spec-compliant server.

The OAuth 2.1 handshake for MCP

  1. 1

    Discovery

    The client fetches the server's OAuth metadata (typically at /.well-known/oauth-authorization-server). This returns the authorization endpoint, token endpoint, registration endpoint, supported scopes, and PKCE methods.

  2. 2

    Dynamic client registration

    The client POSTs to the registration endpoint with its name, redirect URI, and the grant types it supports. The server returns a client_id (and optionally a client_secret for confidential clients). This step is skipped if the client is already registered.

  3. 3

    Authorization request

    The client generates a PKCE code verifier, derives the challenge, and opens the authorization endpoint in the user's browser with client_id, redirect URI, scope, and PKCE challenge. The user signs in to the upstream service and consents to the scopes.

  4. 4

    Token exchange

    The server redirects back to the client with an authorization code. The client POSTs the code plus the PKCE verifier to the token endpoint and receives an access token (and usually a refresh token). The server validates the verifier matches the original challenge before issuing tokens.

  5. 5

    Tool calls

    Subsequent JSON-RPC calls to the MCP server include the access token in the Authorization header. Refresh tokens are exchanged when the access token expires, using stricter rotation rules than OAuth 2.0 — each refresh issues a new refresh token, and the old one is invalidated.

Audience binding and the confused-deputy fix

The spec\'s most important security addition is explicit audience binding. Every access token an MCP server issues is bound to that server\'s audience identifier. If a downstream service calls a different MCP using that token, validation fails. This blocks the classic "I have your token, let me reuse it elsewhere" attack — the token is only valid for the audience it was minted for.

For server authors: include the audience claim in every token you issue and verify it on every request. For client authors: do not pass tokens between servers — request a fresh token per MCP via the OAuth flow even if the upstream service is the same.

What you have to implement

If you build an MCP client

  • OAuth 2.1 authorization code flow with PKCE (required for every public client)
  • Dynamic client registration when the server supports it
  • OS-native credential storage (Keychain / DPAPI / libsecret)
  • Refresh-token rotation handling
  • Browser handoff for the authorization step (system browser, not embedded webview)

If you build a remote MCP server

  • OAuth 2.1 authorization + token endpoints with PKCE validation
  • Dynamic client registration endpoint (RFC 7591)
  • /.well-known/oauth-authorization-server metadata
  • Audience-bound access tokens
  • Refresh-token rotation with single-use refresh tokens
  • Scope enforcement on every MCP method, not just at the auth boundary

Migration path from API keys

If you maintain an MCP server that currently uses API keys, the spec allows you to support both during migration. Keep the API key path for backward compatibility, add the OAuth 2.1 path for new clients, and deprecate the API key path on a published timeline. Most servers complete the transition over one or two release cycles.

The carrot for users: OAuth 2.1 means no more environment-variable token management and no more credential rotation in config files. The carrot for you as a server author: scoped, revocable, audited access by default — the security posture upgrade pays for itself the first time a user accidentally commits a config file.

What not to do

Frequently asked questions

What did the 2025-06-18 MCP spec change about auth?

It standardised on OAuth 2.1 with PKCE for remote (HTTP-based) MCP servers, including dynamic client registration. Before this, every remote server defined its own auth model — API keys, custom tokens, ad-hoc OAuth flows — which made client implementations fragile. The new spec gives every client one auth handshake to implement.

Why OAuth 2.1 and not OAuth 2.0?

OAuth 2.1 is OAuth 2.0 with the deprecated and dangerous parts removed — implicit flow is gone, password grant is gone, PKCE is mandatory for public clients, and refresh tokens have stricter rotation requirements. Standardising on 2.1 means MCP clients do not have to support a permissive superset of OAuth, just the modern subset.

What is dynamic client registration and why does MCP need it?

Dynamic client registration lets an MCP client (Claude Desktop, Cursor, your custom agent) register itself with an MCP server at runtime instead of requiring the server's operator to pre-create a client ID. Without it, every new MCP client would need a manual onboarding step per server. With it, the user installs the MCP, the client registers, the OAuth flow runs, and the user is in.

What does the OAuth flow look like for an MCP user?

User installs the MCP in their client. Client discovers the auth endpoints via the server's metadata. Client dynamically registers itself. Client opens an OAuth 2.1 authorization request (with PKCE) in the user's browser. User signs in to the upstream service and approves the requested scopes. Client receives an authorization code, exchanges it for an access token, and stores it. Subsequent tool calls include the token.

What is the confused-deputy attack the spec warns about?

A confused deputy is when a privileged actor (the MCP server) is tricked by an unprivileged actor (a third party) into using its privileges in unintended ways. In MCP, the classic case is token passthrough: a server receives a token meant for it and re-uses that token to call a different service. The spec requires audience binding so tokens cannot be reused outside their intended audience.

Do local stdio MCPs use OAuth 2.1?

No. Local stdio servers run as subprocesses under the user's account and use whatever credentials the client passes in environment variables — typically API keys for the service the server wraps. OAuth 2.1 is for remote (HTTP) MCPs where the server and the user are on different hosts.

How do I store the OAuth tokens an MCP client receives?

In the OS credential store, not in a config file. Claude Desktop uses Keychain on macOS, DPAPI on Windows, libsecret on Linux. Cursor follows the same pattern. If you are building your own MCP client, use keyring-style libraries that wrap the OS store — never put long-lived tokens in plain files inside the project directory.

Related: MCP Security: What to Know Before You Install · Rotating MCP Credentials

More guides

Fundamentals

What Is MCP? A Plain-English Guide to Model Context Protocol

6 min read

Setup Guide

Best MCPs for Cursor in 2026 (Ranked + Setup)

8 min read

Setup Guide

Best MCPs for Claude Desktop in 2026 (Ranked + Setup)

9 min read

Setup Guide

Best MCPs for Claude Code in 2026 (Ranked + Setup)

8 min read

Setup Guide

Best MCPs for Windsurf in 2026 (Cascade-Ready Setup)

8 min read

Setup Guide

Best MCPs for VS Code in 2026 (Agent Mode + .vscode/mcp.json)

8 min read

Strategy

MCP Registry vs Curated Directory: Which Should You Use?

5 min read

Setup Guide

Best MCPs for ChatGPT: The Apps and Connectors Worth Installing

9 min read

Tutorial

How to Add an MCP Server to ChatGPT (Developer Mode + Apps Directory)

7 min read

Security

MCP Security: What to Know Before You Install

9 min read

Role Guide

Best MCPs for Marketers in 2026 (SEO, Email, Analytics)

8 min read

Strategy

Remote vs Local MCP Servers: When to Use Each

7 min read

Fundamentals

MCP vs Function Calling: What’s the Difference?

6 min read

Comparison

MCP Directories Compared: Top MCPs vs mcp.so vs PulseMCP vs mcp.directory

8 min read

Security

MCP Prompt Injection: How Tool-Calling Agents Get Hijacked

8 min read

Security

Sandboxing MCP Servers: Containers, Least Privilege, and Process Isolation

9 min read

Security

Rotating MCP Credentials: A Practical Guide for Leaks, Expiry, and Routine Hygiene

7 min read

Security

Least-Privilege Scoping for MCPs: How to Grant the Smallest Useful Permission

7 min read

Setup Guide

Best MCP Servers for Databases in 2026 (Ranked + Setup)

10 min read

Setup Guide

Best MCP Servers for Research in 2026 (Search, Scrape, Synthesize)

9 min read

Setup Guide

Best MCP Servers for Design-to-Code in 2026 (Figma → React)

9 min read

Setup Guide

Best MCP Servers for Domains in 2026 (Registrars + DNS)

9 min read

Tutorial

How to Buy a Domain From Claude (Cloudflare MCP, Step by Step)

6 min read

Tutorial

How to Search for Domains With an AI Agent (Cross-Registrar Workflow)

7 min read