Blog · Guides

MCP authorization: how OAuth 2.1 protects Model Context Protocol servers

The MCP authorization spec in practice: the 401 and protected-resource metadata flow, authorization server discovery, dynamic client registration, PKCE, and the resource parameter that binds a token to one MCP server.

Casdoor Team · November 5, 2026 · 4 min read

This guide is written by the team that builds Casdoor and describes the standards as published (listed under Sources), with notes on how Casdoor implements them as of November 5, 2026. Spotted a mistake? Tell us.

A remote MCP server holds tools, data and actions that a model can invoke. Authorization is what stops any client that knows the URL from using them. The Model Context Protocol answers this with OAuth 2.1 and a small set of discovery standards.

Short answer: an HTTP-based MCP server acts as an OAuth 2.1 resource server. A client that has no token gets a 401 with a pointer to the server's protected-resource metadata, discovers the authorization server, registers itself dynamically, runs the authorization code flow with PKCE and a resource parameter, and then sends a bearer token that is scoped to that one MCP server.

The three roles

The MCP authorization spec reuses the OAuth roles:

  • MCP client: the AI application or agent runtime. In OAuth terms it is the client.
  • MCP server: the service exposing tools and resources. In OAuth terms it is the resource server.
  • Authorization server: the system that authenticates the user, gets consent and issues access tokens. It can be the same service as the MCP server or a separate identity provider.

The spec makes authorization optional for MCP implementations, but when an HTTP transport supports it, the implementation should follow the specification. STDIO transports should not use this flow; they should take credentials from the environment.

The flow, step by step

  1. The client calls the MCP server without a token.
  2. The server returns 401 Unauthorized with a WWW-Authenticate header that points at its protected-resource metadata.
  3. The client fetches the metadata document from the server, normally at /.well-known/oauth-protected-resource, and reads the authorization_servers field.
  4. The client fetches the authorization server metadata at /.well-known/oauth-authorization-server, following RFC 8414.
  5. The client registers itself with the authorization server using dynamic client registration (RFC 7591), unless the server provides client credentials another way.
  6. The client generates PKCE parameters and sends the user to the authorization endpoint with the code challenge and the resource parameter.
  7. The authorization server authenticates the user, obtains consent, and redirects back with an authorization code.
  8. The client exchanges the code and the verifier at the token endpoint, again including the resource parameter.
  9. The client calls the MCP server with Authorization: Bearer and the access token.

The spec is deliberate about discovery: MCP clients must use protected-resource metadata to find the authorization server, and must use the authorization server metadata document. Hard-coding endpoints is not the intended design.

What the spec requires

Requirement Level What it means in practice
OAuth 2.1 with appropriate security measures MUST for authorization servers Code flow with PKCE, no implicit flow, exact redirect URI matching
Protected Resource Metadata (RFC 9728) MUST for MCP servers Publish authorization_servers and the resource identifier
Authorization Server Metadata (RFC 8414) MUST for authorization servers Publish endpoints, supported grants and signing keys
Dynamic Client Registration (RFC 7591) SHOULD Let clients register without manual paperwork
PKCE MUST for clients A fresh verifier per authorization request, S256
Resource parameter (RFC 8707) MUST for clients Include the MCP server URI in both the authorization and token requests
Audience validation MUST for servers Reject tokens that were not issued for this server
Bearer token in the Authorization header MUST Never put the token in the query string

Why the resource parameter matters

The resource parameter is the part teams most often skip. It tells the authorization server which API the token is for. Without it, a token issued for one MCP server can be replayed against another server that trusts the same authorization server. With it, the token is bound to the intended audience, and the MCP server can verify that it is the intended recipient.

The spec also forbids token passthrough: if an MCP server calls an upstream API, it must not forward the token it received from the client. It obtains a separate token for the upstream service, as an OAuth client in its own right. This is what prevents the confused-deputy problem where a downstream API trusts a token that was never meant for it.

Common mistakes

  • Using OAuth without PKCE. The MCP spec builds on OAuth 2.1, which requires PKCE for authorization code flows. A client that omits it is not compliant.
  • Skipping protected-resource metadata. A server that only returns a bare 401 forces clients to guess the authorization server. Publish the metadata document.
  • Accepting any bearer token. Validate the issuer, signature, expiry and audience. A token minted for another service is not valid here.
  • Putting tokens in URLs. Bearer tokens belong in the Authorization header, not in query strings or logs.
  • Using OAuth for STDIO servers. Local STDIO servers should read credentials from the environment, not run a browser flow.
  • Passing the client's token upstream. Exchange it for a token that the upstream API issued for the MCP server.

Where Casdoor fits

Casdoor is an OpenID Connect and OAuth 2.0 identity provider that can act as the authorization server in this flow. It supports the authorization code flow with PKCE (S256), publishes authorization server metadata, supports dynamic client registration, and can restrict an application to specific redirect URIs. The MCP server still has to implement protected-resource metadata and audience validation; those are server responsibilities, not the identity provider's.

For the client side, see connecting ChatGPT to an MCP server and adding an MCP server to Claude. For the OAuth mechanics underneath, see PKCE and OAuth for AI agents. Casdoor is open source and self-hostable; Casdoor Cloud starts at $9 per month for a dedicated instance.

Related reading: MCP authorization servers compared, dynamic client registration and token introspection.