MCP authorization explained: how OAuth 2.1 protects a remote MCP server, step by step

Remote MCP servers use OAuth 2.1. The spec picks a small set of RFCs and makes a few of them mandatory. Here is the flow, what each piece stops, and what authorization still leaves to you.

The short answer

MCP authorization is OAuth 2.1 applied to remote MCP servers. The MCP server is an OAuth resource server; the MCP client (Claude, Cursor, an agent framework) is the OAuth client; a separate or co-hosted authorization server signs the user in and issues tokens.1 The server publishes where its authorization server is with Protected Resource Metadata (RFC 9728), the client asks for a token bound to that one server with the resource parameter (RFC 8707), and PKCE protects the code exchange.11

It applies to HTTP transports. Local stdio servers should not use it and take credentials from the environment instead.1 And it answers “who is this client, acting for whom”, not “should this tool call run”.

Every MCP tool call goes through your rules first. Here a delete that doesn’t say which rows is stopped before it reaches the database. These are the rules deedglass init starts with; the call is made up.

Who plays which role

The spec builds on the OAuth 2.1 draft plus a short list of RFCs: 6750 (bearer tokens), 8414 (authorization server metadata), 7591 (dynamic registration), 8707 (resource indicators), 9728 (protected resource metadata) and 9207 (issuer identification), along with OpenID Connect Discovery and the Client ID Metadata Document draft.1

Role In MCP Its job
Resource server The MCP server Accept only tokens issued for it1
Client The MCP client or agent host Discover, register, get a token, send it on every request1
Authorization server Your IdP, or one built into the server Sign the user in, issue tokens1
Resource owner The user Consent to what the client may do

Authorization is optional in MCP. A server that holds nothing sensitive can skip it.1 Once you support it over HTTP, the spec’s MUSTs apply.

The flow, step by step

Here is the path a client takes the first time it meets a protected server, following the spec’s sequence:

  1. The client calls the server without a token. The server answers 401 with a WWW-Authenticate header pointing at its Protected Resource Metadata, and ideally a scope hint.1
  2. The client reads the metadata at the URL given, which names the authorization server(s). Servers must publish this document and clients must use it to find the authorization server.1
  3. The client discovers the authorization server’s endpoints through RFC 8414 metadata or OpenID Connect Discovery; clients must support both.1
  4. The client gets a client ID, by one of three methods covered below.2
  5. The client opens the browser with an authorization request carrying a PKCE code_challenge (S256), the resource parameter naming the MCP server, and the chosen scopes. It records which issuer it expects.1
  6. The user signs in and consents. The authorization server redirects back with a code, and should include iss.1
  7. The client checks iss against the issuer it recorded, then exchanges the code plus the PKCE code_verifier and the resource parameter for a token.1
  8. Every MCP request carries the token in the Authorization: Bearer header, never in the query string.1

Getting a client ID

Desktop and agent clients usually have no prior relationship with a server they’ve just been pointed at. The spec offers three ways to get a client ID, in this priority order for clients that support all of them:2

Method When Status in 2026-07-28
Pre-registration Client and server already know each other Supported2
Client ID Metadata Documents No prior relationship (the common case) Should be supported1
Dynamic Client Registration (RFC 7591) Older authorization servers Deprecated, kept for compatibility2

A Client ID Metadata Document turns the client ID into an HTTPS URL. The client hosts a small JSON file at that URL with its name and redirect URIs; the authorization server fetches it, checks that the client_id inside matches the URL exactly, and only accepts redirect URIs listed there.2 That removes the need for every server to run an open registration endpoint, which is where several earlier problems came from. Our post on the confused deputy problem shows one.

The rules that stop real attacks

Most of the MUSTs exist because of a specific, known attack:

Rule Stops
Send resource (RFC 8707) in authorization and token requests1 A token for server A being replayed at server B
Servers must validate the token was issued for them, and must not accept or pass through other tokens1 Token passthrough: a server forwarding your upstream token, or accepting one meant elsewhere
PKCE with S256; refuse to proceed if the server doesn’t advertise code_challenge_methods_supported3 A stolen authorization code being redeemed by someone else
Check iss against the recorded issuer1 Mix-up attacks, where a malicious authorization server collects a code issued by an honest one
HTTPS for authorization endpoints; redirect URIs must be localhost or HTTPS3 Interception and open redirects
Tokens in headers, never query strings1 Tokens leaking into logs and browser history

The token passthrough rule deserves emphasis. If your MCP server calls GitHub or Salesforce on the user’s behalf, it gets its own token from that upstream service. It must not forward the token the MCP client gave it, and it must not accept a GitHub token from the client in place of its own.3

One rule isn’t in this list because it sits outside OAuth: clients must treat the authorization URL a server hands them carefully. The mcp-remote flaw, where a crafted authorization_endpoint from a malicious server led to command injection, is the cautionary tale4; see our write-up.

Scopes and step-up

Scopes are how a server says what a token allows. The spec asks servers to include a scope hint in the 401 challenge, and clients to request the minimum they need at first.1 When a token is too weak for a particular call, the server answers 403 with error="insufficient_scope" and the scopes required, and the client runs a step-up authorization for a broader token, keeping the scopes it already had.1

That’s a good pattern for agents. An agent can start with files:read, and when it tries to write, the user sees a fresh consent screen for files:write. It turns a hidden escalation into a visible one.

But scopes are coarse. files:write doesn’t say which file, how many, or whether the agent should be deleting the folder it’s in. That decision still has to happen somewhere else.

What authorization doesn’t cover

Authorization done well tells a server, reliably, which client is calling for which user, with which scopes. It does not tell anyone:

  • Whether a particular call is a good idea. A correctly authorized agent with db:write can still run DELETE without a WHERE.
  • What actually changed. A token says nothing about the outcome of a call. If an agent says it updated one row, you still need to check.
  • Anything about local servers. stdio servers take credentials from the environment and fall outside this spec.1 Most coding-agent setups still run local servers, with whatever keys sit in their config.
  • Prompt injection. A properly scoped token used by a manipulated agent does what the attacker asked, within scope. See prompt injection.

That’s why authorization and per-call policy are separate layers. A gateway or the server itself decides call by call, ideally with an approval for risky ones. Our MCP server security basics puts the layers together.

A checklist for server builders

  1. Serve Protected Resource Metadata and return 401 with a WWW-Authenticate pointer and a scope hint.11
  2. Validate every token’s audience is your server; reject everything else.1
  3. Never forward the client’s token upstream; get your own.3
  4. Keep scopes_supported minimal and use 403 insufficient_scope for step-up.1
  5. Prefer Client ID Metadata Documents over open dynamic registration.2
  6. Require PKCE S256, HTTPS endpoints and exact redirect URIs.3
  7. Add per-call policy and logs on top. Authorization says who; it doesn’t say what’s safe.

For what changed elsewhere in the latest revision, read our MCP 2026-07-28 summary. To try call-by-call approvals on a real database in your browser, open the playground; to grade the MCP servers and keys your agents can reach on your own machine, run npx deedglass scan (the grade, explained).

Written with AI assistance and checked against our claims register.

The takeaway

MCP authorization binds a token to one server with RFC 8707 and PKCE, but it says who the client is, not which tool calls are safe; stdio servers skip it.

Read nextMCP 2026-07-28: what changed, and what it means for anyone in the middle Try it: install in 7 s

Related on this site

Terms

In the docs

More posts

Sources

  1. 1MCP specification 2026-07-28: Authorization · modelcontextprotocol.io · checked 27 October 2026
  2. 2MCP specification 2026-07-28: Client registration · modelcontextprotocol.io · checked 27 October 2026
  3. 3MCP specification 2026-07-28: Authorization security considerations · modelcontextprotocol.io · checked 27 October 2026
  4. 4JFrog: Critical RCE vulnerability in mcp-remote, CVE-2025-6514 · jfrog.com · checked 26 October 2026

Published 27 October 2026, sources last checked 27 October 2026. If something here is out of date, write to hello@deedglass.com.

Try it on your own setup

npx deedglass scan

Grades only your own setup. Nothing is uploaded.

Pricing