MCP OAuth is the authorization flow the Model Context Protocol uses when an MCP client calls a protected MCP server over HTTP on a user's behalf. The MCP server acts as an OAuth 2.1 resource server, an authorization server issues short-lived access tokens, and the client discovers that server, signs the user in with PKCE and sends the token as a Bearer header on every request.
Authorization is optional in the Model Context Protocol, but remote servers holding user data need it. Revision 2026-07-28 of the MCP authorization specification makes Client ID Metadata Documents the preferred way to register a client, marks Dynamic Client Registration as deprecated, and requires clients to check the issuer on every authorization response, so older guides describe a flow that is no longer the default.
Bifrost, the open-source AI gateway, handles MCP OAuth on both sides of the gateway: it is the authorization server for the clients that connect to it and the OAuth client for the upstream MCP servers it calls.
How does OAuth work for MCP servers?
OAuth works for MCP servers through a challenge, discover and retry sequence. The client sends a request without a token, the MCP server answers 401 Unauthorized with a WWW-Authenticate header, and the client follows that header to the authorization server, gets the user's consent in a browser, and retries with a Bearer token.

Figure 1: The MCP server only validates tokens; the authorization server handles sign-in, consent and token issuance.
The six steps run against the server's MCP endpoint and the authorization server it names:
- Challenge. The server returns
401with aresource_metadataURL and, optionally, the required scopes. - Discover. The client fetches the protected resource metadata, picks an issuer from
authorization_servers, and fetches its metadata. - Register. The client gets a client ID through a metadata document, pre-registration or Dynamic Client Registration.
- Authorize. The browser opens with a PKCE
code_challengeand aresourceparameter; the client records thestate, verifier and expected issuer. - Exchange. The client checks
isson the callback, then trades the code andcode_verifierfor an access token and, if issued, a refresh token. - Call. The client sends
Authorization: Beareron every request, and the server rejects tokens issued for another audience.
A typical challenge looks like this:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer resource_metadata="https://mcp.example.com/.well-known/oauth-protected-resource",
scope="files:read"
Why does MCP use OAuth 2.1 with PKCE?
MCP uses OAuth 2.1 because most MCP clients are public clients, such as desktop apps, IDEs and CLIs, that cannot keep a client secret. OAuth 2.1 folds OAuth 2.0 and its security extensions into one profile and makes PKCE mandatory for the authorization code flow.
PKCE (Proof Key for Code Exchange) binds the authorization code to the client that asked for it. The client sends a SHA-256 hash of a random code_verifier as the code_challenge and reveals the verifier at the token endpoint, so a stolen code is useless. MCP clients must use the S256 method and must refuse to continue when the authorization server's metadata does not list code_challenge_methods_supported.
| Behavior | OAuth 2.0 (RFC 6749 and extensions) | OAuth 2.1 as MCP uses it |
|---|---|---|
| PKCE | Optional extension (RFC 7636) | Required, with S256 |
| Implicit grant | Allowed | Removed |
| Resource owner password grant | Allowed | Removed |
| Redirect URI matching | Exact match not required | Exact match against registered URIs |
| Access token in URL query | Allowed by RFC 6750 | Forbidden; Authorization header only |
| Refresh tokens for public clients | No rotation rule | Must be rotated |
| Token audience | Not defined | resource parameter (RFC 8707) binds the token to one MCP server |
How does an MCP client discover the authorization server?
An MCP client discovers the authorization server in two hops. It reads the protected resource metadata the MCP server publishes, takes an issuer from its authorization_servers list, and then fetches that issuer's metadata from an OAuth 2.0 or OpenID Connect well-known endpoint.
What is protected resource metadata?
Protected resource metadata is a JSON document, defined in RFC 9728, in which a resource server describes itself: its resource identifier, the authorization_servers that issue tokens for it, and optionally scopes_supported. Every MCP server must publish one, and every MCP client must use it. Clients take its URL from the resource_metadata parameter of WWW-Authenticate; otherwise they probe /.well-known/oauth-protected-resource, first with the endpoint path appended, then at the root.
Authorization server metadata: RFC 8414 and OpenID Connect
MCP clients must support both OAuth 2.0 Authorization Server Metadata (RFC 8414) and OpenID Connect Discovery 1.0, because many OpenID Connect (OIDC) providers publish only the second. For an issuer without a path, the client tries /.well-known/oauth-authorization-server and then /.well-known/openid-configuration. The issuer inside the document must match the URL it was built from exactly, or the client discards it.
How does client registration work in MCP OAuth?
An MCP client needs a client ID before it can start the authorization flow, and MCP defines three ways to get one. Because MCP clients and servers usually have no prior relationship, revision 2026-07-28 prefers Client ID Metadata Documents and keeps Dynamic Client Registration only for authorization servers that do not support them.
| Order | Mechanism | How the client gets an ID | Signal in authorization server metadata | Status in 2026-07-28 |
|---|---|---|---|---|
| 1 | Pre-registration | An admin registers the client in advance | None | Use when available |
| 2 | Client ID Metadata Documents | The client_id is an HTTPS URL that serves a JSON document with client_name and redirect_uris | client_id_metadata_document_supported | SHOULD support |
| 3 | Dynamic Client Registration (RFC 7591) | The client posts its metadata to the registration endpoint and receives credentials | registration_endpoint | MAY support; deprecated |
Dynamic Client Registration was the default in earlier revisions: the client posts its name and redirect URIs to /register and gets back a client_id. Every client then leaves a registration on the authorization server, and servers that keep registrations in memory lose them on restart. Client IDs are also scoped to the server that issued them, so a client keeps separate registrations and tokens for each authorization server, as the current MCP specification requires.
How do scopes and step-up authorization work in MCP?
Scopes limit what an MCP OAuth token can do, and the MCP server tells the client which ones a request needs. The scope in the 401 challenge is authoritative for that request; when it is absent, the client requests the scopes_supported list from protected resource metadata, which should list only the minimum set.
| Response | Meaning | What the client does |
|---|---|---|
401 Unauthorized | No token, or the token is invalid or expired | Run discovery and authorization, or use a refresh token |
403 Forbidden with error="insufficient_scope" | The token is valid but lacks a scope; the header lists the required scopes | Re-authorize with the union of earlier and challenged scopes, then retry |
400 Bad Request | The authorization request is malformed | Fix the request; retrying will not help |
Re-authorizing for a broader scope is called step-up authorization. Servers should list every scope an operation needs in one challenge, and clients should cap retries. Many teams map scopes to groups of tools, as in OAuth scopes and per-tool permissions for MCP.
MCP OAuth security risks
Most MCP OAuth failures come from tokens reaching places they should not: a token issued for one server accepted by another, a client token forwarded to an upstream API, or an authorization code sent to the wrong authorization server. The MCP security best practices name each case and its required control. Risks outside OAuth, such as tool poisoning, are covered in MCP security.
- Token passthrough. An MCP server must accept only tokens whose audience is itself and must never forward a client's token upstream; third-party APIs get their own token.
- Confused deputy. A proxy MCP server with one static client ID at a third-party authorization server must get user consent for each dynamically registered client, or a stolen code yields tokens without consent.
- Mix-up attacks. Clients compare the response's
isswith the recorded issuer as plain strings (RFC 9207), so a malicious authorization server cannot capture another server's code. - Code and redirect theft. Redirect URIs must be
localhostor HTTPS and match exactly; clients verifystate, and PKCE makes an intercepted code worthless. - Token theft. Access tokens should be short-lived, refresh tokens for public clients must rotate, and both must be stored securely.
A shared MCP gateway also cuts the number of places tokens live and gives one point to revoke them.
How do you add OAuth to a remote MCP server?
Adding OAuth to a remote MCP server means turning it into an OAuth resource server and pairing it with an authorization server, usually the identity provider the organization already runs. The MCP server validates tokens; it does not handle passwords, consent screens or token issuance itself.
- Choose the authorization server, often an existing OpenID Connect provider. Its metadata must list
code_challenge_methods_supportedwithS256, and it should support Client ID Metadata Documents or Dynamic Client Registration. - Publish protected resource metadata with the server's canonical URI, such as
https://mcp.example.com/mcp, and return401withWWW-Authenticateon unauthenticated requests. - Define scopes for groups of tools, and keep
scopes_supportedto the minimum. - Validate every token for signature, expiry, issuer and audience; answer
401for invalid tokens and403withinsufficient_scopefor missing permissions. - Keep upstream credentials separate. For a user's third-party account, the server acts as an OAuth client to that service, sending the user there through URL mode elicitation.
- Serve it over HTTPS on Streamable HTTP, the transport the authorization flow is defined for.
MCP OAuth with Bifrost
Bifrost, the open-source AI gateway built by Maxim AI, handles MCP OAuth on two separate legs. Inbound, it is the OAuth 2.1 authorization server for clients that connect to its /mcp endpoint. Outbound, it is the OAuth client for each upstream MCP server that uses OAuth, holding a token issued for that server alone.

Figure 2: The client's token ends at the gateway; each upstream server receives a token issued for it.
With gateway authentication set to oauth or both, Bifrost answers unauthenticated /mcp requests with 401 and WWW-Authenticate, serves RFC 9728 and RFC 8414 metadata, accepts Dynamic Client Registration, uses PKCE S256, and binds tokens to /mcp through the audience claim. Claude Code, Cursor and Claude Desktop then connect without a pasted key.
On the consent page, the user binds the grant to a virtual key, an anonymous session or an SSO user, and the virtual key's budgets, rate limits and tool access apply to the token. Access tokens are JWTs valid for 600 seconds by default, refresh tokens rotate on each use, and an admin can revoke any grant.
Outbound, each MCP client in Bifrost has one of six auth types. Three use OAuth:
oauthkeeps one admin-authorized token with automatic refresh, PKCE and endpoint discovery, encrypted at rest.per_user_oauthasks each user to authorize on their first tool call and stores the token against their identity, listed on the MCP Sessions page (per-user OAuth).token_exchangeswaps the caller's identity-provider token for one scoped to the upstream server through RFC 8693 token exchange, storing nothing per user.
Because inbound and upstream tokens are separate, a client's token never passes through to an upstream server, as the specification requires. The Bifrost MCP gateway adds tool filtering and audit logs on the same path.
To put OAuth in front of your MCP servers, start with the gateway quickstart.
Frequently asked questions
Do local stdio MCP servers need OAuth?
No. The MCP authorization specification covers HTTP-based transports, and it says stdio implementations should not follow it. A local server launched as a subprocess reads credentials from its environment, such as an API key in an environment variable, because the user who starts it controls the machine. MCP authentication compares this with OAuth and static API keys.
Is MCP OAuth based on OAuth 2.0 or OAuth 2.1?
MCP OAuth is based on OAuth 2.1, which builds on OAuth 2.0 rather than replacing it. Authorization servers must implement OAuth 2.1, so PKCE is mandatory and the implicit and password grants are gone. It also relies on OAuth 2.0 extensions such as RFC 6750 Bearer tokens, RFC 8707 resource indicators and RFC 9728 protected resource metadata.
What is the difference between MCP authentication and MCP authorization?
Authentication establishes who the user or client is; authorization decides what that identity may do on a given MCP server. In MCP, the authorization server authenticates the user, usually through the organization's identity provider, and issues a token with scopes. The MCP server then authorizes each request by checking the token's audience and scopes.
Does MCP OAuth require Dynamic Client Registration?
No. Revision 2026-07-28 deprecates Dynamic Client Registration and keeps it for backward compatibility. Clients should use pre-registered credentials first, then Client ID Metadata Documents when the authorization server advertises support, then Dynamic Client Registration if it offers a registration endpoint.
- mcp oauth
- mcp authorization
- mcp gateway



