MCP authorization makes an HTTP server an OAuth resource server that advertises its authorization server via 401 and RFC 9728 metadata
DrFritzi · Reviewed · Updated 28 Sept 2026 · Markdown
Answer
In MCP, authorization is optional and applies to HTTP transports. A protected MCP server is an OAuth 2.1 resource server. It must publish OAuth 2.0 Protected Resource Metadata (RFC 9728) that names at least one authorization server in authorization_servers. An unauthenticated request gets 401 with a WWW-Authenticate header that can carry a resource_metadata URL. The client discovers the authorization server, registers, runs an authorization code flow with PKCE and an RFC 8707 resource parameter, and sends Authorization: Bearer <token> on every request. This page describes specification 2026-07-28, the latest revision. Servers on stdio SHOULD NOT follow this flow and instead get credentials from the environment.
Details
Step by step
| # | Client action | Server response |
|---|---|---|
| 1 | MCP request without a token | MCP server: 401 Unauthorized, WWW-Authenticate: Bearer resource_metadata="https://mcp.example.com/.well-known/oauth-protected-resource", optionally scope="files:read" |
| 2 | GET the resource_metadata URL. Without that parameter, try /.well-known/oauth-protected-resource/<endpoint path>, then /.well-known/oauth-protected-resource |
MCP server: metadata with authorization_servers |
| 3 | Pick an authorization server, GET its metadata (/.well-known/oauth-authorization-server, then /.well-known/openid-configuration) |
Authorization server: metadata. The issuer must equal the issuer used to build the URL |
| 4 | Check that code_challenge_methods_supported is present, otherwise stop |
|
| 5 | Get a client ID (see below) | Authorization server |
| 6 | Browser to the authorization endpoint with code_challenge (S256), resource, scopes |
Authorization server: user consents, redirects with a code (and iss) |
| 7 | Token request with code_verifier and resource |
Authorization server: access token |
| 8 | MCP request with Authorization: Bearer <token> |
MCP server: validates audience, then answers. Bad or expired token: 401. Insufficient scope: 403 with error="insufficient_scope" |
Client registration
Clients that support every option SHOULD prefer, in order: pre-registered client information, Client ID Metadata Documents (when the authorization server sets client_id_metadata_document_supported), Dynamic Client Registration (when it offers a registration_endpoint), then asking the user. With a Client ID Metadata Document, the client_id is an HTTPS URL with a path that serves a JSON document with at least client_id, client_name and redirect_uris. Dynamic Client Registration (RFC 7591) is deprecated in this revision and kept for backwards compatibility.
Server duties
- Validate that the token was issued for this server as audience, and reject others (RFC 8707).
- Never pass the received token to an upstream API. If you call one, use a separate token from that API's authorization server.
- The
resourcevalue is the server's canonical URI, for examplehttps://mcp.example.com/mcp, with no fragment.
Common mistakes
- Serving no Protected Resource Metadata at all. The spec requires one of the
WWW-Authenticateheader or a well-known URI. - Accepting any valid token from the same authorization server without an audience check.
- Forwarding the client's token to a third-party API.
- Putting the access token in the URL query string. The spec forbids it.
- Treating
scopeas fixed. Clients must treat the challenged scopes as authoritative for the current operation. - Applying this flow to a stdio server.
See also
Sources
- MCP Specification 2026-07-28 — Authorization
- MCP Specification 2026-07-28 — Authorization Server Discovery
- MCP Specification 2026-07-28 — Client Registration
- MCP Specification 2026-07-28 — Authorization Security Considerations
- RFC 9728 — OAuth 2.0 Protected Resource Metadata
- RFC 8707 — Resource Indicators for OAuth 2.0