MCP OAuth is the authorization path for remote Model Context Protocol servers that need to protect user data or sensitive actions. The client discovers the server’s authorization setup, obtains an access token through OAuth 2.1, and sends that token only to the MCP server it was issued for.

Applies to: Model Context Protocol specification revision 2026-07-28, checked October 27, 2026. This guide explains the protocol contract; it does not report a hands-on interoperability test.

On this page

Where MCP OAuth applies

The MCP authorization specification is for HTTP-based transports. A protected MCP server acts as an OAuth resource server. The MCP client acts as an OAuth client on the resource owner’s behalf. A separate authorization server can handle sign-in, consent and token issuance.

Authorization is optional at the protocol level, but it is the relevant path when a remote server exposes private files, account data, administrative operations or anything else that should not be public. Local stdio servers are different: the MCP specification says they should obtain credentials from their environment instead of applying this HTTP authorization flow.

That distinction prevents a common design mistake. Adding OAuth to a local child process does not automatically make it safer, and passing a local API key to a remote HTTP endpoint is not a substitute for a well-defined authorization boundary. Start by choosing the right transport, as explained in the MCP stdio vs Streamable HTTP guide.

The flow in one table

Step Client action Server or metadata response
1. Challenge Calls the protected MCP endpoint 401 Unauthorized with a WWW-Authenticate challenge
2. Resource discovery Reads Protected Resource Metadata Learns the canonical resource URI, authorization server and supported scopes
3. Authorization discovery Reads OAuth or OpenID Connect metadata Learns the authorization and token endpoints plus supported features
4. Client registration Obtains a client ID Uses Client ID Metadata Documents, pre-registration or legacy dynamic registration
5. User authorization Opens the authorization-code flow with PKCE User signs in and grants the requested access
6. Token exchange Exchanges the code and includes the resource identifier Receives a token intended for this MCP server
7. MCP request Sends Authorization: Bearer ... Server validates the token, audience and scopes

The important part is discovery. A client should not require every MCP server to share one hard-coded authorization endpoint or one registration method.

Start with Protected Resource Metadata

When the client first reaches a protected endpoint without a usable token, the server returns HTTP 401. The preferred challenge includes a resource_metadata pointer:

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer resource_metadata="https://mcp.example.com/.well-known/oauth-protected-resource",
                         scope="files:read"

The referenced Protected Resource Metadata document identifies the MCP resource and one or more authorization servers:

{
  "resource": "https://mcp.example.com/mcp",
  "authorization_servers": ["https://auth.example.com"],
  "scopes_supported": ["files:read", "files:write"]
}

The 2026-07-28 specification requires servers to implement OAuth 2.0 Protected Resource Metadata. Clients must support both the WWW-Authenticate pointer and the well-known URI fallback. If the metadata lists several authorization servers, each is independent: client IDs, tokens and saved registration state must stay bound to the issuer that created them.

Discover the authorization server before redirecting

After selecting an authorization server, the client fetches its metadata through either OAuth Authorization Server Metadata or OpenID Connect Discovery. That document tells the client where the authorization and token endpoints live and which features the issuer supports.

Do not construct /authorize and /token paths by convention. The advertised endpoints are authoritative. The client must also keep the validated issuer value with the PKCE verifier and request state so it can detect mix-up attacks when the browser returns from authorization.

The current MCP revision prefers three ways to obtain a client ID, in this order defined by the specification:

  1. an OAuth Client ID Metadata Document;
  2. a client ID registered in advance;
  3. Dynamic Client Registration, retained for compatibility.

Dynamic Client Registration is no longer the main recommendation. A server may support it, but a client cannot assume that every authorization server exposes a registration endpoint.

Bind the token to the MCP resource

The client must send the OAuth resource parameter in both the authorization request and the token request. Its value is the canonical URI of the MCP server, ideally the most specific URI that identifies the protected endpoint:

resource=https%3A%2F%2Fmcp.example.com%2Fmcp

That parameter is not cosmetic. It lets the authorization server issue a token for a particular resource instead of a vague token that might be replayed at another service. The MCP server must then verify that the token was issued for it.

Use the same canonical resource consistently in Protected Resource Metadata, authorization requests, token requests and audience validation. A missing scheme, a URI fragment or an accidental mismatch between a host-level resource and a path-level resource can break interoperability or weaken the boundary.

Require PKCE and validate the issuer

MCP clients must use the OAuth authorization-code flow with PKCE. Before starting the flow, the client checks authorization-server metadata for code_challenge_methods_supported. If support is absent, the current security requirements say the client must refuse to proceed. Use S256 when technically capable.

PKCE protects the authorization code from being redeemed by a different process. It does not replace the other checks. A client also needs to:

  • associate the verifier, state and expected issuer with the same authorization attempt;
  • compare a returned iss value with the recorded issuer when the response includes it;
  • reject a response when metadata says iss will be present but the response omits it;
  • match the exact registered redirect URI;
  • keep access and refresh tokens out of URLs and logs.

Authorization endpoints must use HTTPS. Redirect URIs must use HTTPS or a localhost address. A localhost redirect is useful for installed clients, but the authorization screen should still show the hostname clearly so users can spot an unexpected destination.

Request the smallest useful scopes

The server can include a scope parameter in its initial 401 challenge. The client should treat that scope set as authoritative for the current operation. If the challenge has no scope, the client can use the minimal scopes_supported set from Protected Resource Metadata.

Do not request every permission up front merely because the authorization server advertises it. The current specification supports step-up authorization: an MCP request that needs more access can return HTTP 403 with error="insufficient_scope" and a scope challenge. The client then asks the user for the additional scopes while preserving previously granted ones.

For server authors, challenge with all scopes required for the current operation at once. Returning one missing scope per retry creates repeated browser round trips without adding security.

Send bearer tokens only in the header

Authenticated MCP requests carry the token in the HTTP header:

POST /mcp HTTP/1.1
Host: mcp.example.com
Authorization: Bearer <access-token>

The token must not appear in the query string. It should be included on every protected HTTP request, and the resource server must validate it before processing the request.

Use HTTP 401 when the token is absent, invalid or expired. Use HTTP 403 when the token is valid but lacks the required scope. Keeping those cases separate lets a client decide whether it should sign in again or request more permission.

Never pass an MCP token through to another API

An MCP server often acts as a bridge to an upstream service. The inbound MCP token is still meant for the MCP server, not for that upstream API. Passing it through would ignore its audience and can turn the server into a confused deputy.

If the MCP server calls another API, it should act as an OAuth client to that API and obtain a separate upstream token. Keep the two token sets, audiences and consent decisions separate. The MCP specification explicitly forbids token passthrough.

This is also why copying an access token between different MCP servers is wrong even when they share a vendor or authorization server. A token must be accepted only by the resource it targets.

A deployment checklist

Before exposing a protected remote MCP server, verify these items against the current specification and your authorization product:

  • Protected Resource Metadata is reachable through the challenge and well-known discovery paths.
  • The metadata’s resource value matches the server’s canonical URI.
  • At least one advertised authorization server has valid OAuth or OpenID Connect metadata.
  • The client registration method is documented and supported.
  • PKCE support is advertised and the client uses S256.
  • Authorization and token requests both include the same resource parameter.
  • Tokens are checked for signature, expiry, audience and required scopes.
  • Tokens never appear in query strings, application logs or upstream API calls.
  • 401 and 403 responses carry useful, standards-based challenges.
  • Refresh tokens, if issued, are stored confidentially and rotated where required.

For a client-specific example of adding a server, see Codex MCP setup. To compare maintained integrations rather than inventing configuration, browse the site’s MCP server directory.