How MCP Added OAuth Authorization
MCP's authorization evolved from each server issuing tokens to a cleaner three-role model.

The first version of the MCP spec, released in November 2024, said essentially nothing about authorization. That wasn't an oversight so much as a prioritization call: get the protocol working first, sort out security later. Understandable. Also the kind of decision that compounds.
By March 2025, the spec had authorization coverage, but the structural choice it made created more problems than it solved. MCP servers were designated as their own OAuth authorization servers. Every team shipping an MCP server suddenly owned token issuance, client registration, key management, and the full surface area of OAuth edge cases. Security machinery that takes dedicated teams years to harden was now a prerequisite for exposing a tool that searched a knowledge base or queried a database. That's not a reasonable ask, and the spec acknowledged it implicitly by correcting course three months later.
The June 2025 revision got the architecture right. MCP servers were reclassified as OAuth Resource Servers. The separation of concerns became clean: the MCP server validates tokens and enforces permissions; a dedicated authorization server handles token issuance. Resource Indicators (RFC 8707) became a requirement, meaning tokens were now explicitly scoped to a specific server rather than floating freely across a deployment. A dedicated security best-practices page appeared for the first time.
November 2025 solved a more practical problem: how clients identify themselves without pre-registration. That revision introduced Client ID Metadata Documents as the recommended default and introduced the Enterprise-Managed Authorization extension, which gets its own section below.
The July 2026 revision, the current one, is the largest since launch. Sessions were removed entirely, making the protocol stateless; every request becomes independently verifiable without relying on accumulated session state. Six Security Enhancement Proposals tighten alignment with production OAuth 2.0 and OpenID Connect deployments. The spec also signals that the iss (issuer) field in tokens, currently a SHOULD requirement, is on a trajectory toward MUST.
Why does any of this history matter? Because none of these revisions were cosmetic. Each one corrected a real structural mistake made in a prior version. If you encounter an implementation built against the March 2025 spec, you are looking at a server that believes it should be issuing its own tokens. That is a distinct security posture from what the spec prescribes today, and the difference is not subtle.
The three-role architecture the current spec establishes
The current spec establishes three roles, and the boundaries between them are doing most of the security work.
The MCP server is an OAuth 2.1 Resource Server. Its job is to validate tokens and enforce permissions on the tools and resources it exposes. It does not issue tokens. Handling user login is explicitly outside its responsibility.
The MCP client is an OAuth 2.1 client. It makes protected resource requests on behalf of a resource owner, either a user or an organization, depending on the deployment context.
The authorization server is separate from both. It interacts with the user when consent or authentication is required, and it issues access tokens. The spec is deliberate that this is a dedicated service, not a feature bolted onto the MCP server.
The boundary between the MCP server and the authorization server is where the most real-world trouble originates. Collapse two distinct security responsibilities into a single service and you don't just create operational complexity; teams shipping tools end up making implicit security decisions they didn't know they were making, about key management, token lifetimes, client validation, revocation. The June 2025 revision recognized that and drew the line.
One wrinkle worth holding onto: when an MCP server needs to call an upstream API, it must act as an OAuth client to that service and obtain separate tokens. It cannot pass through the token it received from the MCP client. The spec explicitly prohibits this because passing a received token upstream creates what security practitioners call a confused deputy vulnerability, where a service uses credentials granted for one purpose to take actions in a different context, often with broader authority than anyone intended. The server that does this isn't being efficient; it's laundering authorization.
One more boundary the spec draws clearly: this authorization model applies to HTTP-based transports. The STDIO transport should not follow it and should retrieve credentials from the environment instead. Authorization is formally optional in the spec, but for any server touching real data or enterprise systems, treating that optionality as a default is a policy decision with real consequences.
What happens on the wire: the authorization flow from 401 to access token
Start at the entry point. A client attempts to access a protected resource without a token. The server returns HTTP 401 Unauthorized, with a WWW-Authenticate header that includes a resource_metadata URL. That URL is where everything that follows begins.
The client fetches a Protected Resource Metadata document, defined in RFC 9728. MCP servers must implement this; MCP clients must use it for authorization server discovery. The PRM document tells the client which authorization servers are associated with this MCP server, and if multiple are listed, the client chooses among them.
From there, the client constructs an authorization request, and here the Resource Indicators requirement from RFC 8707 becomes critical. The resource parameter must appear in both the authorization request and the subsequent token request, identifying the MCP server by its canonical URI. The effect is that the authorization server issues a token scoped and valid only for that specific server. Without audience binding, a compromised server can take a token it received legitimately and replay it against a different protected resource. RFC 8707 forecloses that possibility, provided the MCP server actually validates the audience claim.
PKCE, Proof Key for Code Exchange, matters more in the MCP context than it appears at first. In traditional OAuth deployments, PKCE protects against authorization code interception. In MCP deployments, its significance runs deeper because many MCP clients are agents, containers, or serverless functions running in environments where storing a client secret securely is either difficult or simply not feasible. PKCE replaces the need for a static secret by binding the authorization code to a one-time verifier generated at the moment of the request. The secret is ephemeral by design.
When the token arrives at the MCP server, validation is not optional. The server must validate per OAuth 2.1 Section 5.2 and verify that the token's intended audience matches its own resource identifier. Tokens issued by unauthorized servers must be rejected. Invalid or expired tokens must return HTTP 401. The server must not transit tokens it receives to other services.
The 2026 stateless core closes one path worth noting: tokens can no longer rely on session state to supplement their claims. Every request must carry sufficient context to be verified independently. If an implementation was relying on session continuity to patch over incomplete token claims, that path is now closed.
How clients identify themselves: the shift from DCR to CIMD
Dynamic Client Registration was the original answer to how MCP clients identify themselves to authorization servers. The problem is that DCR at MCP scale creates pressures the mechanism was never designed to absorb.
A developer building a new AI agent cannot manually pre-register with every MCP server in a public registry; there are too many, and new ones appear continuously. Many authorization servers don't support DCR at all. And open DCR endpoints are, by their nature, unauthenticated write APIs sitting on security infrastructure, with authorization servers accumulating large numbers of ephemeral client records with weak attribution and security teams with limited visibility into who built or operates a given client.
The November 2025 spec introduced Client ID Metadata Documents as its answer. A CIMD is a JSON document hosted at a stable HTTPS URL that the client developer controls. That URL becomes the OAuth client_id. Identity becomes web-based rather than registry-based. Authorization servers fetch the URL on demand to learn client metadata; no pre-registration is required. Redirect URIs are bound to the client within its own metadata document, which is structurally harder for an attacker to manipulate than an open registration endpoint.
The priority order in the spec is worth knowing: pre-registered credentials first, then CIMD if the authorization server advertises support, then DCR if a registration endpoint is available, then manual entry as a last resort. CIMD is the SHOULD default; DCR is demoted to MAY.
Ecosystem adoption moved quickly. By April 2026, Keycloak shipped experimental CIMD support; WorkOS incorporated it into AuthKit; Auth0 and Authlete announced implementations. AT Protocol and Bluesky had already adopted URL-based client identity in 2024, while the CIMD draft was still circulating, citing the same rationale.
There is a class of clients CIMD cannot help: desktop applications, CLI tools, IDE plugins, internal agents deployed behind a firewall. These clients cannot host a public document at a stable HTTPS URL. For them, DCR or pre-registration remain the available paths, and the stronger attestation and platform-level guarantees that would make those paths more robust remain open questions in the spec. CIMD solves the problem it was designed to solve. It doesn't pretend to solve the whole space.
Enterprise-Managed Authorization: centralized policy across MCP servers
Before the Enterprise-Managed Authorization extension, standard MCP OAuth had a practical gap that enterprise security teams found untenable. Every employee who needed to use an MCP-connected tool had to manually authenticate to each MCP server individually. There was no mechanism for a security team to enforce consistent access policy centrally, and no consolidated audit trail across server connections. A user inadvertently connects a personal account to a work tool, and IT has no visibility into which AI tools are communicating with which internal systems. Not hypothetical; the actual default state.
EMA addresses this by shifting authorization governance to the organization. End users access all connected MCP servers through a single corporate login. The mechanism underneath is ID-JAG, Identity JWT Authorization Grant, which the IETF OAuth Working Group adopted in September 2025.
The flow is deliberate. A user authenticates to the MCP client via corporate SSO. The client takes the resulting ID token to the enterprise identity provider and requests access to a specific MCP server. The IdP checks corporate policy: is this user in the right role? Is this team permitted to use this tool against this system? If policy passes, the IdP issues an ID-JAG. The client presents that assertion to the MCP authorization server, which issues an access token. No additional user interaction. No per-server consent screen.
Okta's Cross App Access implementation is the foundation EMA builds on. The MCP spec incorporated it in November 2025 and declared it stable as a formal authorization extension in June 2026. At launch, seven providers had implemented it: Asana, Atlassian, Canva, Figma, Granola, Linear, and Supabase. Slack support was in progress; HubSpot, Ramp, and Webflow were rolling out enterprise implementations. Anthropic's own EMA deployment is the first live production instance.
What EMA does not solve matters just as much as what it does. It governs who can connect to which MCP servers under what organizational policy. Governing what a connected agent does once it has access is a different problem, entirely outside EMA's scope. Prompt injection attacks, where an adversarial input manipulates an agent into misusing legitimately held permissions, remain a runtime risk. Supply chain risks from malicious third-party MCP servers are similarly out of bounds. EMA is a policy and identity layer, not a behavioral one. Treating it as both produces a false sense of coverage.
What goes wrong when OAuth is implemented carelessly
In March 2026, researchers scanned 15,923 MCP servers and AI skills for security vulnerabilities. The findings were discouraging: 757 servers were actively leaking API keys through tool outputs; 36 percent of servers scored a failing grade; not a single tool in the dataset earned an 'A'; 42 skills were confirmed malicious after LLM verification. That last finding deserves a moment. This was not an audit of early prototypes or abandoned experiments. This was the current landscape.
CVE-2025-6514, discovered by JFrog Security Research Team, affected mcp-remote versions 0.0.5 through 0.1.15 and carried a CVSS score of 9.6. The vulnerable component was the client-side bridging layer. The attack surface in MCP OAuth isn't only the server; the client, the transport layer, and the tooling developers reach for when building integrations are all in scope.
The confused deputy pattern comes up repeatedly in deployed servers. Passing through the token received from an MCP client to an upstream API is the path of least resistance when you're building quickly. The spec explicitly prohibits it, but that prohibition is only effective if the developer reads the security guidance, understands why it exists, and builds accordingly. Many don't.
Token audience validation failures are quieter and more common. An authorization server that doesn't enforce audience claims, combined with an MCP server that fails to validate them, means a token issued for one resource can be presented at another. The RFC 8707 requirement exists precisely because this failure mode is predictable and the consequences extend across an entire deployment.
Redirect URI manipulation was a documented attack vector before CIMD made the problem structurally harder. Open DCR endpoints permitted registration of malicious redirect URIs, enabling authorization code interception. CIMD's binding of redirect URIs to the client's own metadata document is a direct architectural response to that class of attack.
Scope over-provisioning is the failure mode that looks the least like a failure until something goes wrong. Issuing tokens with broad scopes because defining fine-grained ones requires more upfront work means a compromised agent can act far beyond what the task it was given actually requires. The blast radius of any single compromised token expands accordingly.
None of these are failures of OAuth 2.1 as a protocol. The protocol provides audience binding, PKCE, scope enforcement, redirect URI validation. Each requires a deliberate choice to implement correctly, and each is optional in the sense that skipping it doesn't break the handshake. It just removes the protection.
What "governed" looks like when OAuth is implemented as the spec intends
A fully spec-compliant MCP server provides a minimum set of guarantees that clarify what "secure" actually means in this context.
Every token carries verified identity: who authorized the action, via which client, on behalf of which user or organization. Tokens are audience-bound via RFC 8707, so a token valid for one MCP server cannot be replayed against another. Scopes are defined and enforced, so agents operate under minimal privilege. PKCE means agents running in ephemeral environments, containers, serverless functions, automation scripts, do not need to manage a stored secret.
Layer EMA on top and the posture changes qualitatively for enterprise deployments. IT and security teams get centralized policy enforcement across every MCP server connection in the organization: one place to grant access, one place to revoke it, one consolidated audit trail.
That audit trail is where the distinction between a governed deployment and a merely functional one becomes legible. Knowing what an agent did is useful. Knowing in real time what an agent is doing, which user authorized it, which organizational policy permitted the connection, and whether that policy has since changed: that is what separates a deployment you can reason about from one you can only investigate after the fact.
The TypeScript and Python SDKs each crossed one billion total downloads as of mid-2026. At that scale, the gap between a deployed MCP server and a governed one is not an academic concern. The spec provides the mechanisms. Whether teams shipping servers treat them as defaults or as optional guidance is, increasingly, a decision with consequences well outside their own systems.


