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/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:
{
"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:
{
"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:
- pre-registered client information for this server, if the client has it;
- a Client ID Metadata Document, if the authorization server advertises
client_id_metadata_document_supported; - Dynamic Client Registration, if the authorization server publishes
registration_endpoint; - 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.
{
"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:
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.comIssuer 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/1.1 302 Found
Location: http://127.0.0.1:3000/callback?code=SplxlOBeZQQYbYS6WxSbIA&state=af0ifjsldkj&iss=https%3A%2F%2Fauth.example.comPOST /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%2FmcpUsing 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:
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/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
localhostor 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
localhostredirect 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.
MCP authorization and related mechanisms
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
- Authorization, specification 2026-07-28(opens in a new tab)
- Authorization Server Discovery, specification 2026-07-28(opens in a new tab)
- Client Registration, specification 2026-07-28(opens in a new tab)
- Authorization Security Considerations, specification 2026-07-28(opens in a new tab)
- Key Changes, specification 2026-07-28(opens in a new tab)
- Authorization, specification 2025-03-26(opens in a new tab)
- Key Changes, specification 2025-06-18(opens in a new tab)
- Key Changes, specification 2025-11-25(opens in a new tab)
- Enterprise-Managed Authorization(opens in a new tab)
- The OAuth 2.1 Authorization Framework, draft-ietf-oauth-v2-1-13(opens in a new tab)
- RFC 6749: The OAuth 2.0 Authorization Framework(opens in a new tab)
- RFC 9728: OAuth 2.0 Protected Resource Metadata(opens in a new tab)
- RFC 8414: OAuth 2.0 Authorization Server Metadata(opens in a new tab)
- RFC 8707: Resource Indicators for OAuth 2.0(opens in a new tab)
- RFC 9207: OAuth 2.0 Authorization Server Issuer Identification(opens in a new tab)
- RFC 7636: Proof Key for Code Exchange by OAuth Public Clients(opens in a new tab)
- RFC 7591: OAuth 2.0 Dynamic Client Registration Protocol(opens in a new tab)
- OAuth Client ID Metadata Document, draft-ietf-oauth-client-id-metadata-document-00(opens in a new tab)