MCP Authorization
The most widely implemented authorization profile written specifically for agents and tools.
Flows / Human present
How an MCP client that has never seen a server before discovers where to sign in, identifies itself, and gets a token good for that server alone.
The Model Context Protocol has a problem classic OAuth never had to solve: any client may meet any server, with no prior arrangement. A user pastes in a server URL, and the client has to work out which authorization server protects it, introduce itself to that server, and obtain a token, all at runtime.
MCP answers this with a profile of OAuth 2.1 plus three discovery steps. The MCP server is an OAuth resource server. It points to its authorization server through protected resource metadata. The client identifies itself with a URL that the authorization server can fetch, called a Client ID Metadata Document, instead of registering in advance. Every token is bound to one MCP server through the resource parameter.
This page describes the 2026-07-28 revision of the specification. Authorization is optional in MCP and applies to HTTP transports; a server launched over stdio takes its credentials from its environment.
14 steps between 4 parties. Each step shows the message and who holds which credential afterward. Use ←→ or select any arrow.
Drag to see every party and step. Tap a step to jump to its explanation.
The user has added a server URL. The client simply tries a request.
The WWW-Authenticate header can carry the URL of the server’s protected resource metadata and the scopes needed for this request. The header is optional. If it is missing, the client constructs the well-known URL itself, trying the path-specific form before the root.
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer
resource_metadata="https://mcp.example.com/.well-known/oauth-protected-resource/mcp",
scope="files:read"This document (RFC 9728) is the bridge between a resource and its authorization server. It must list at least one entry in authorization_servers. scopes_supported is meant to be the minimal set for basic use, not everything the server could ever ask for.
{
"resource": "https://mcp.example.com/mcp",
"authorization_servers": ["https://auth.example.com"],
"scopes_supported": ["files:read"],
"bearer_methods_supported": ["header"]
}This exchange shows OAuth authorization server metadata (RFC 8414). An MCP authorization server must publish that or OpenID Connect Discovery metadata, and a conforming client must support both: it tries the RFC 8414 location first, then the OpenID one. Three checks happen here. The issuer in the document must be identical to the one used to build the URL. code_challenge_methods_supported must be present, or the client must refuse to continue. And the client looks for client_id_metadata_document_supported to decide how to identify itself.
{
"issuer": "https://auth.example.com",
"authorization_endpoint": "https://auth.example.com/authorize",
"token_endpoint": "https://auth.example.com/token",
"code_challenge_methods_supported": ["S256"],
"client_id_metadata_document_supported": true,
"authorization_response_iss_parameter_supported": true
}Preference order: credentials pre-registered for this server; otherwise a Client ID Metadata Document if the server supports them; otherwise Dynamic Client Registration (deprecated); otherwise ask the user. With a metadata document the client_id is an HTTPS URL the client’s publisher controls.
The client also creates a PKCE verifier and records the validated issuer alongside it, to check the response against later.
// served at https://app.example.com/oauth/client.json
{
"client_id": "https://app.example.com/oauth/client.json",
"client_name": "Example Agent",
"redirect_uris": ["http://127.0.0.1:3000/callback"],
"grant_types": ["authorization_code", "refresh_token"],
"token_endpoint_auth_method": "none"
}Who holds what after this step
Parties not listed hold none of this flow’s credentials at this point.
Authorization code with PKCE, plus the resource parameter set to the canonical URI of the MCP server. Clients must send resource on both the authorization request and the token request, whether or not the authorization server is known to support it.
GET /authorize?response_type=code
&client_id=https://app.example.com/oauth/client.json
&redirect_uri=http://127.0.0.1:3000/callback
&scope=files:read
&resource=https://mcp.example.com/mcp
&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
&code_challenge_method=S256
&state=xyzABC123 HTTP/1.1
Host: auth.example.comWho holds what after this step
Parties not listed hold none of this flow’s credentials at this point.
Seeing a URL as client_id, the server fetches it. The client_id inside the document must match the URL exactly, and the redirect URI in the request must be listed in it. Because this is a server fetching a URL chosen by a stranger, it needs the usual protections against server-side request forgery, and may apply its own policy about which client domains it trusts.
Who holds what after this step
Parties not listed hold none of this flow’s credentials at this point.
The server shows the client’s name from the metadata document and must clearly display the redirect URI’s hostname. A client that redirects only to localhost deserves a warning, since anything on the machine can claim that address.
Who holds what after this step
Parties not listed hold none of this flow’s credentials at this point.
Authorization servers should include the iss parameter (RFC 9207), and the specification signals that this will become mandatory.
GET /callback?code=SplxlOBeZQQYbYS6WxSbIA
&state=xyzABC123
&iss=https://auth.example.com HTTP/1.1
Host: 127.0.0.1:3000Who holds what after this step
Parties not listed hold none of this flow’s credentials at this point.
Before sending the code anywhere, the client compares iss with the issuer it recorded, as a plain string comparison. If the server advertised that it sends iss and none arrived, the client rejects the response. An MCP client deals with many authorization servers, some of them hostile; this check stops one from harvesting codes meant for another.
Who holds what after this step
Parties not listed hold none of this flow’s credentials at this point.
With the PKCE verifier and, again, the resource parameter. There is no redirect_uri here: MCP builds on OAuth 2.1, which removed it from the token request.
POST /token HTTP/1.1
Host: auth.example.com
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=SplxlOBeZQQYbYS6WxSbIA
&client_id=https://app.example.com/oauth/client.json
&code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
&resource=https://mcp.example.com/mcpWho holds what after this step
Parties not listed hold none of this flow’s credentials at this point.
The client stores it against this issuer and this server. A refresh token may or may not be issued; clients must not assume one.
Who holds what after this step
Parties not listed hold none of this flow’s credentials at this point.
The token goes in the Authorization header on every request. As of 2026-07-28 MCP has no sessions and no initialization handshake, so the bearer token is the only thing identifying the caller from one request to the next. The Mcp-Method and Mcp-Name headers let a gateway apply per-tool policy without parsing the body.
POST /mcp HTTP/1.1
Host: mcp.example.com
Authorization: Bearer eyJhbGciOiJFUzI1NiIsInR5cCI6ImF0K2p3dCJ9…
Mcp-Method: tools/call
Mcp-Name: search_files
Content-Type: application/json
{"jsonrpc":"2.0","id":2,"method":"tools/call",
"params":{"name":"search_files","arguments":{"query":"Q3 plan"}}}Who holds what after this step
Parties not listed hold none of this flow’s credentials at this point.
The server must confirm the token was issued for it and reject anything else. If the tool needs a scope the token lacks, it answers 403 with an insufficient_scope challenge listing everything the operation needs, and the client runs a step-up for the union of old and new scopes.
Who holds what after this step
Parties not listed hold none of this flow’s credentials at this point.
The 2026-07-28 revision is published and current, but two things this page draws rest on IETF working-group drafts. The revision requires authorization servers to implement OAuth 2.1 and cites draft -13; the current draft is -17. It recommends Client ID Metadata Documents, which steps 4 to 8 use, and cites draft -00; the current draft is -03. Either draft can still change. The rating describes those dependencies. It is not a judgment on how safe the flow is.
2025-03-26. First authorization framework. The MCP server doubled as the authorization server.
2025-06-18. The MCP server became a resource server. Protected resource metadata and resource indicators became mandatory; token passthrough was prohibited.
2025-11-25. Client ID Metadata Documents became the preferred way to identify a client and Dynamic Client Registration became optional. Step-up through insufficient_scope challenges and URL-mode elicitation were added.
2026-07-28. The protocol became stateless. Dynamic Client Registration was deprecated, issuer validation (RFC 9207) was added, client credentials were bound to their issuer, and the client-credentials and enterprise-managed authorization extensions were declared stable.
The same discovery steps apply to machine-to-machine use. The official OAuth Client Credentials extension has the client authenticate with a signed JWT assertion (recommended) or a secret, with pre-registered credentials. See client credentials.
See the full tracker for status and links.
What the flow implements, shows in a step, or must support. These decide its maturity rating.
The most widely implemented authorization profile written specifically for agents and tools.
The baseline MCP profiles. Worth knowing that the normative base of most agent authorization is still, formally, a draft.
The preferred way for an MCP client to identify itself to a server it has never met.
How an agent that has only a server URL finds out where to get a token. MCP servers must implement it.
Zero-configuration discovery. MCP clients must support this and OpenID Connect discovery.
Required by MCP. An agent talks to many servers; this is what stops a token for one being replayed at another.
The defense against mix-up attacks for clients that use many authorization servers. Clients must validate it under MCP 2026-07-28.
Mandatory for MCP clients, which must also refuse to proceed if a server does not advertise support.
An MCP authorization server publishes this or RFC 8414 metadata, and an MCP client must support both. It is also the format Kubernetes clusters and CI systems use to publish workload-identity signing keys.
The default way agents present tokens, and the thing proof-of-possession schemes are trying to replace.
Variants and additions the page mentions. No step depends on them, and the flow does not require them.
The original answer for MCP. It left authorization servers with unbounded anonymous registrations, which is why MCP moved away from it.
The baseline. A person signs in, approves specific scopes, and the agent receives a token that says so.
A tool needs the user to sign in somewhere else. It hands back a link, the user completes the flow in a browser, and the secret never touches the agent.
The company identity provider decides which agents may reach which apps for which employees. No per-app consent screens.
Start with a weak token. When the agent reaches something sensitive, the API says so and the user is asked for exactly that.