Registrati

Authorization in MCP

This article is not available in Italian yet. It is shown in English.

Authorization in MCP is the part of the Model Context Protocol specification that defines how an MCP client obtains an access token for a protected MCP server and presents it with every HTTP request. It is built on OAuth 2.1 and a set of related IETF standards. The MCP server acts as an OAuth resource server, and a separate authorization server issues the tokens.

Authorization first appeared in the specification 2025-03-26 and has changed in every revision since. This article describes the current version of the specification, 2026-07-28, and notes what changed in earlier versions. Basic concepts of the protocol (host, client, server, transports) are described in the article What is MCP.

Overview

Property Value
Type Authorization at the transport level, optional
Applies to HTTP-based transports; stdio servers take credentials from the environment
Basis OAuth 2.1 (IETF draft), a selected subset of its features
Roles MCP server as resource server, MCP client as OAuth client, authorization server
Token Bearer access token in the Authorization header of every request
Discovery Protected Resource Metadata (RFC 9728); Authorization Server Metadata (RFC 8414) or OpenID Connect Discovery 1.0
Client registration Client ID Metadata Documents, pre-registration, Dynamic Client Registration (deprecated)
Required protections PKCE with S256, resource indicators (RFC 8707), issuer validation (RFC 9207)
Specification version 2026-07-28

The problem it solves

A remote MCP server often serves many users and has to know who sends a request and what that user has allowed. A token in a configuration file is issued by hand for each server and stored in a predictable location on disk.

MCP clients are general-purpose: a host can connect to a server with which it has no prior relationship. OAuth 2.0 (RFC 6749) assumes the opposite: the client registers before the flow and learns the endpoints from the documentation of the service.

The specification solves this with a chain of standard documents. The server answers an unauthenticated request with HTTP 401 and a link to its metadata, which names the authorization server. The client identifies itself with a URL of its own metadata document, so no prior registration is needed. The resulting token is bound to one MCP server.

History

The table shows how authorization changed across the versions of the specification.

Date Event
November 2024 Specification 2024-11-05: authorization is not defined
26 March 2025 Specification 2025-03-26: authorization based on OAuth 2.1, Authorization Server Metadata (RFC 8414) with default paths /authorize, /token, /register
18 June 2025 Specification 2025-06-18: the MCP server is classified as an OAuth resource server and publishes Protected Resource Metadata (RFC 9728). Clients must send resource indicators (RFC 8707). Token passthrough is forbidden; a Security Best Practices page is added
25 November 2025 Specification 2025-11-25: Client ID Metadata Documents recommended, Dynamic Client Registration optional, OpenID Connect Discovery 1.0, scopes in WWW-Authenticate
28 July 2026 Specification 2026-07-28: validation of iss in the authorization response (RFC 9207), credentials bound to the issuer, application_type in Dynamic Client Registration, Dynamic Client Registration deprecated

Roles

The specification defines three participants and a user agent:

  • Resource server is the protected MCP server. It accepts requests with access tokens, checks them and answers.
  • OAuth client is the MCP client. It makes requests on behalf of the resource owner, usually the user of the host.
  • Authorization server interacts with the user, if needed, and issues access tokens for use at the MCP server. It can be hosted together with the MCP server or separately; the specification does not define its implementation.
  • User agent is the browser in which the user signs in and gives consent.

When authorization applies

Authorization is optional. When an implementation supports it, the requirements depend on the transport:

  • an implementation over an HTTP-based transport should follow the authorization specification;
  • an implementation over stdio should not follow it and takes credentials from the environment, for example from environment variables set by the host;
  • an implementation over another transport must follow the established security practices of that transport.

The transports themselves are described in the article Transports in MCP.

The complete flow

The diagram shows the flow from the first request without a token to the first request with a token. The client ID comes from one of the registration mechanisms described below.

Browser              MCP client                   MCP server              Authorization server
   |                      |                            |                            |
   |                      |-- request without token -->|                            |
   |                      |<- 401, WWW-Authenticate ---|                            |
   |                      |-- GET resource metadata -->|                            |
   |                      |<- authorization_servers ---|                            |
   |                      |-- GET authorization server metadata ------------------->|
   |                      |<- endpoints, PKCE, iss support -------------------------|
   |                      |   record issuer, PKCE      |                            |
   |<- authorization URL -|                            |                            |
   |-- code_challenge, resource, scope -------------------------------------------->|
   |                      |                            |                            | user signs in, consents
   |<- redirect: code, state, iss --------------------------------------------------|
   |-- code, state, iss ->|                            |                            |
   |                      |   compare iss with issuer  |                            |
   |                      |-- token request, code_verifier ------------------------>|
   |                      |<- access token, refresh token --------------------------|
   |                      |-- request + Bearer token ->|                            |
   |                      |<- MCP response ------------|                            |

Discovery

Protected resource metadata

An MCP server must implement OAuth 2.0 Protected Resource Metadata (RFC 9728). Its metadata document must contain the authorization_servers field with at least one authorization server. The server makes the document discoverable in one of two ways: it puts the URL in the resource_metadata parameter of the WWW-Authenticate header of a 401 response, or it serves the document at a well-known URI.

A response to a request without a token can look like this:

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

If the header has no resource_metadata, the client builds well-known URIs and tries them in order. For an MCP endpoint https://example.com/public/mcp the first one is https://example.com/.well-known/oauth-protected-resource/public/mcp, with the path inserted after the well-known prefix. The second one is the root: https://example.com/.well-known/oauth-protected-resource. Clients must support both discovery mechanisms.

The metadata document of the server from the example above:

JSON
{
  "resource": "https://mcp.example.com/mcp",
  "authorization_servers": ["https://auth.example.com"],
  "scopes_supported": ["files:read", "files:write"],
  "bearer_methods_supported": ["header"],
  "resource_name": "Example MCP Server"
}

According to RFC 9728, the resource value must match the URL that the client used to call the server; otherwise the client must not use the document.

Authorization server metadata

An authorization server must provide at least one of two discovery mechanisms: OAuth 2.0 Authorization Server Metadata (RFC 8414) or OpenID Connect Discovery 1.0. Clients must support both and try several well-known URLs in a fixed order.

Issuer URLs in order of priority
With a path, https://auth.example.com/tenant1 /.well-known/oauth-authorization-server/tenant1, /.well-known/openid-configuration/tenant1, /tenant1/.well-known/openid-configuration
Without a path, https://auth.example.com /.well-known/oauth-authorization-server, /.well-known/openid-configuration

The issuer value in the received document must be identical to the issuer identifier from which the URL was built. A document fetched from an attacker's host that claims another issuer must be rejected.

A shortened example of authorization server metadata with the fields that matter for MCP:

JSON
{
  "issuer": "https://auth.example.com",
  "authorization_endpoint": "https://auth.example.com/authorize",
  "token_endpoint": "https://auth.example.com/token",
  "response_types_supported": ["code"],
  "grant_types_supported": ["authorization_code", "refresh_token"],
  "code_challenge_methods_supported": ["S256"],
  "scopes_supported": ["files:read", "files:write", "offline_access"],
  "client_id_metadata_document_supported": true,
  "authorization_response_iss_parameter_supported": true
}

Client registration

Before the authorization flow the client must obtain a client ID. The specification defines three mechanisms. A client that supports all of them should use them in this order:

  1. pre-registered client information for this server, if the client has it;
  2. a Client ID Metadata Document, if the authorization server advertises client_id_metadata_document_supported;
  3. Dynamic Client Registration, if the authorization server publishes registration_endpoint;
  4. a prompt to the user to enter client information.

Client ID Metadata Documents

With Client ID Metadata Documents the client ID is an HTTPS URL that points to a JSON document with the client's metadata. The URL must use the https scheme and contain a path. The document must contain at least client_id, client_name and redirect_uris, and client_id must match the URL of the document exactly.

JSON
{
  "client_id": "https://app.example.com/oauth/client-metadata.json",
  "client_name": "Example MCP Client",
  "client_uri": "https://app.example.com",
  "redirect_uris": ["http://127.0.0.1:3000/callback"],
  "grant_types": ["authorization_code", "refresh_token"],
  "response_types": ["code"],
  "token_endpoint_auth_method": "none"
}

When the authorization server sees a client ID in URL form, it fetches the document, checks client_id and the redirect URI of the request and caches the document according to HTTP cache headers. The mechanism is based on an IETF draft.

Pre-registration

Clients should support static client credentials: a client ID built into the client for a specific authorization server, or a form where the user enters a client ID registered by the user.

Dynamic Client Registration

Dynamic Client Registration (RFC 7591) lets a client obtain a client ID with a request to the registration_endpoint of the authorization server, without user interaction. It is deprecated since 2026-07-28 and kept for compatibility with authorization servers that do not support Client ID Metadata Documents. A client that uses it must specify an application_type: native for desktop, CLI and local web applications, web for remote web applications.

Binding credentials to the authorization server

Pre-registered credentials and credentials saved after Dynamic Client Registration belong to the authorization server that issued them. The client must store them keyed by that server's issuer. If the protected resource metadata starts naming another authorization server, the client must not reuse the old credentials and must register again. Client IDs based on Client ID Metadata Documents are portable: the authorization server resolves the URL on demand, so a change of server needs no new registration.

Authorization request and token

PKCE

PKCE (Proof Key for Code Exchange, RFC 7636) protects the authorization code from interception. Before the request the client creates a random code_verifier and sends its SHA-256 hash, the code_challenge, in the authorization request. In the token request the client sends the code_verifier itself, so only the client that started the flow can redeem the code.

MCP clients must implement PKCE and must use the S256 method when technically capable. OAuth does not define how to discover PKCE support, so the client checks code_challenge_methods_supported in the authorization server metadata. If the field is absent, the client must refuse to proceed. An authorization server that offers OpenID Connect Discovery must include this field for MCP compatibility.

Resource indicators

A resource indicator (RFC 8707) is the resource parameter that names the server for which the token is requested. MCP clients must send it in both the authorization request and the token request, even if the authorization server does not support it. The value is the canonical URI of the MCP server: an absolute URI with a scheme and without a fragment, for example https://mcp.example.com/mcp or https://mcp.example.com. The form without a trailing slash is recommended.

An authorization request with all required parameters:

HTTP
GET /authorize?response_type=code&client_id=https%3A%2F%2Fapp.example.com%2Foauth%2Fclient-metadata.json&redirect_uri=http%3A%2F%2F127.0.0.1%3A3000%2Fcallback&scope=files%3Aread&state=af0ifjsldkj&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM&code_challenge_method=S256&resource=https%3A%2F%2Fmcp.example.com%2Fmcp HTTP/1.1
Host: auth.example.com

Issuer validation

In a mix-up attack a malicious authorization server tries to make the client send it a code or token issued by another, honest server (RFC 9207). PKCE does not prevent this, because the client would send its code_verifier to the attacker's token endpoint.

Before opening the browser the client must record the issuer from the validated metadata, together with the PKCE verifier and state. Authorization servers should add the iss parameter to authorization responses and advertise this with authorization_response_iss_parameter_supported. The client checks the response before it sends the code to any token endpoint:

authorization_response_iss_parameter_supported iss in the response Client action
true present Compare with the recorded issuer
true absent Reject the response
false or absent present Compare with the recorded issuer
false or absent absent Proceed

The comparison is a simple string comparison without any normalization. It applies to error responses too: on a mismatch the client does not show error, error_description or error_uri.

A redirect that passes the check and the token request that follows it:

HTTP
HTTP/1.1 302 Found
Location: http://127.0.0.1:3000/callback?code=SplxlOBeZQQYbYS6WxSbIA&state=af0ifjsldkj&iss=https%3A%2F%2Fauth.example.com
HTTP
POST /token HTTP/1.1
Host: auth.example.com
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA&redirect_uri=http%3A%2F%2F127.0.0.1%3A3000%2Fcallback&client_id=https%3A%2F%2Fapp.example.com%2Foauth%2Fclient-metadata.json&code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk&resource=https%3A%2F%2Fmcp.example.com%2Fmcp

Using the access token

The client sends the token in the Authorization header with the Bearer scheme. The header must be present in every HTTP request to the server, not only in the first one. The token must not be placed in the query string of the URI. Since 2026-07-28 there is also no protocol session: each request carries its own authorization.

A request to call a tool with a token:

HTTP
POST /mcp HTTP/1.1
Host: mcp.example.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Content-Type: application/json
Accept: application/json, text/event-stream
MCP-Protocol-Version: 2026-07-28
Mcp-Method: tools/call
Mcp-Name: read_file

{"jsonrpc": "2.0", "id": 7, "method": "tools/call", "params": {"name": "read_file", "arguments": {"path": "report.md"}, "_meta": {"io.modelcontextprotocol/protocolVersion": "2026-07-28", "io.modelcontextprotocol/clientCapabilities": {}}}}

The server validates the token as OAuth 2.1 requires and checks that the token was issued for it as the audience. An invalid or expired token gets HTTP 401. The server must not accept or pass on tokens issued for other resources. The client must not send the server tokens issued by any other authorization server.

When the MCP server calls another API, it acts as a separate OAuth client of that API with a separate token. Forwarding the client's token (token passthrough) is forbidden.

Errors and scopes

Status codes

The table lists the HTTP status codes that a server returns for authorization errors.

Code Meaning When it is used
401 Unauthorized Authorization is required or the token is invalid
403 Forbidden Invalid scopes or insufficient permissions
400 Bad Request Malformed authorization request

Scope selection

A scope is a named permission that a token carries, such as files:read. The server should include a scope parameter in the WWW-Authenticate header of the 401 response with the scopes needed for the resource. For the first authorization the client takes the scopes from this parameter. If the parameter is absent, it requests all scopes from scopes_supported in the protected resource metadata, or omits scope if that field is absent too.

The client treats the scopes in a challenge as authoritative for the current operation, whatever their relation to scopes_supported. scopes_supported is meant to hold a minimal set for basic functionality. Servers should not list offline_access there or in a challenge, because refresh tokens are not a requirement of the resource.

Step-up authorization

Step-up authorization is a request for a new token with more scopes when the current token is not sufficient for an operation. A server that receives such a token should answer HTTP 403 with error="insufficient_scope", the required scopes and resource_metadata:

HTTP
HTTP/1.1 403 Forbidden
WWW-Authenticate: Bearer error="insufficient_scope", scope="files:write", resource_metadata="https://mcp.example.com/.well-known/oauth-protected-resource/mcp", error_description="File write permission required for this operation"

The client computes the union of the scopes it requested before and the scopes from the challenge, starts authorization again and repeats the original request. The union keeps permissions that other operations still need. The server should name all scopes required for the operation in one challenge. Clients should limit retries; clients acting on their own behalf, with client_credentials, may abort the request instead. Servers must take scope hierarchies into account, where a broader scope implies a narrower one.

Refresh tokens

A refresh token lets the client obtain a new access token without the user. A client that wants refresh tokens must keep them confidential, should include refresh_token in grant_types of its metadata and may request offline_access if the authorization server lists it. The client must not assume that a refresh token will be issued.

Authorization servers should issue short-lived access tokens and must rotate refresh tokens for public clients.

Security requirements

The Security Considerations of the specification cover these attacks:

  • token theft: tokens are stored securely;
  • communication security: authorization server endpoints use HTTPS, redirect URIs are localhost or HTTPS;
  • open redirection: redirect URIs are registered and compared exactly, the client checks state;
  • mix-up attacks: the client validates iss;
  • confused deputy: an MCP proxy server obtains user consent for each client;
  • Client ID Metadata Document risks: request forgery when documents are fetched, impersonation of localhost redirect URIs.

These and other risks are described in the article MCP security, checks of a server's authorization behavior in Testing MCP servers.

Authorization extensions

Two official extensions cover cases beyond interactive user consent. OAuth Client Credentials defines machine-to-machine access. Enterprise-Managed Authorization (io.modelcontextprotocol/enterprise-managed-authorization) lets an organization control access to MCP servers through its identity provider, so employees do not authorize each server separately. Extensions are described in the article MCP extensions.

Several mechanisms in and around MCP deal with credentials. The table shows how they differ.

Mechanism Who is authorized Where the credentials come from Who holds them
Credentials from the environment A local stdio server at an external service Environment variables, configuration of the host The server process
MCP authorization The MCP client at the MCP server OAuth flow with the server's authorization server The MCP client
URL mode elicitation The MCP server at a third-party API OAuth flow or form opened by the server in the browser The MCP server
Enterprise-Managed Authorization The MCP client at the MCP server The organization's identity provider The MCP client

MCP authorization protects the MCP server itself. A server that needs access to a third-party service on behalf of the user obtains it separately, through URL mode elicitation: the server sends the user to a URL, and the credentials never pass through the client. The server must not use URL mode elicitation to authorize users for itself.

The two flows never share tokens. Elicitation requests travel through Multi Round-Trip Requests, described in the article Stateless MCP.

Terms

Term Meaning
Resource server Server that accepts requests with access tokens; in MCP, the protected MCP server
Authorization server Service that authenticates the user and issues access tokens for the MCP server
Protected Resource Metadata JSON document of the MCP server (RFC 9728) that names its authorization servers and scopes
Client ID Metadata Document JSON document at an HTTPS URL that serves as the client ID and describes the client
PKCE Proof Key for Code Exchange: a verifier and its hash that bind the authorization code to the client that requested it
Resource indicator resource parameter (RFC 8707) that names the MCP server for which a token is requested
Scope Named permission carried by an access token
Step-up authorization Request for a token with more scopes after a 403 response with insufficient_scope
Mix-up attack Attack in which a malicious authorization server obtains a code or token issued by another server
Refresh token Token that lets the client obtain a new access token without the user

Sources

Series

Model Context Protocol (MCP)
  1. What is MCP (Model Context Protocol)
  2. Tools in MCP
  3. Resources and resource templates in MCP
  4. Prompts in MCP
  5. MCP transports: stdio and Streamable HTTP
  6. Stateless MCP: changes in 2026-07-28
  7. Authorization in MCPCurrent
  8. MCP security
  9. MCP extensions
  10. MCP server over an existing API
  11. Testing MCP servers: the basics
  12. Evaluating an MCP server with models
  13. Regression testing of an MCP server
  14. Publishing an MCP server to the MCP Registry

Wiki articles are written and maintained by the ComplexQA team.