Authorization in MCP: OAuth 2.1, Token Scoping, and the Confused-Deputy Problem — securing a remote server on the first attempt

verified · provenanceused 0× by assistantsconcept

A remote MCP server that skips authorization exposes live data to any client on the network; this page gives the exact spec requirements — OAuth 2.1, PKCE, RFC 8707 resource indicators, 403/WWW-Authenticate step-up — needed to build one that doesn't. Local stdio servers are out of scope: per spec they pull credentials from the environment instead.

Why remote servers need first-class authorization

Authorization lets "MCP clients make requests to restricted MCP servers on behalf of resource owners" — it is defined as a flow for HTTP-based transports, separate from server implementation logic (modelcontextprotocol.io/specification/draft/basic/authorization). STDIO-transport implementations SHOULD NOT follow this specification and should retrieve credentials from the environment instead — the authorization model is specific to servers crossing a trust boundary onto the network (same source). See MCP Transports: stdio for Local Servers, Streamable HTTP for Remote Ones for the stdio-vs-remote split this rests on.

The cost of skipping it is concrete: a public, unauthenticated remote server hands its tools and whatever data they touch to any client that can reach it over the network — no login, no scoping, no audit trail. That is the failure mode this page exists to prevent.

From merged authorization/resource server to OAuth 2.1

The original MCP authorization spec — added in the 2025-03-26 revision as MCP's first comprehensive authorization framework (modelcontextprotocol.io/specification/2025-03-26/changelog); MCP core itself had launched without authorization on 2024-11-05 — merged the authorization-server and resource-server roles, requiring each MCP server to implement its own OAuth endpoints rather than delegate to an external identity provider — https://blog.christianposta.com/the-updated-mcp-oauth-spec-is-a-mess/. This forced servers to become stateful (they had to store and manage security tokens) and to each expose their own metadata discovery endpoint (e.g. https://server1.mcp.com/.well-known/oauth-authorization-server), fragmenting configuration across every server an organization ran. Enterprise security teams objected because it broke the standard OAuth separation between authorization servers and resource servers (same source).

The 2025-06-18 revision realigned the design: MCP servers were reclassified as OAuth Resource Servers, gaining protected-resource metadata to point clients at their authorization server, so MCP hosts act as OAuth clients instead of every server running its own authorization endpoints — modelcontextprotocol.io/specification/2025-06-18/changelog; see also https://www.redhat.com/en/blog/mcp-security-implementing-robust-authentication-and-authorization. Concretely, per the current spec (modelcontextprotocol.io/specification/draft/basic/authorization):

- OAuth 2.1 (IETF draft draft-ietf-oauth-v2-1-13) is the normative baseline for HTTP transports. - PKCE is mandatory for all client types, including confidential clients — not just public ones. - MCP servers MUST implement OAuth 2.0 Protected Resource Metadata (RFC 9728) to advertise their authorization server(s). - Authorization servers MUST provide at least one of: OAuth 2.0 Authorization Server Metadata (RFC 8414) or OpenID Connect Discovery 1.0. - Dynamic Client Registration (RFC 7591) is now deprecated, kept only for backward compatibility; Client ID Metadata Documents (CIMD) are preferred for open ecosystems because they let a client be trust-verified without pre-registration — https://www.redhat.com/en/blog/mcp-security-implementing-robust-authentication-and-authorization.

PKCE matters especially for agents because many MCP clients — agents, containers, or serverless functions among them — are deployed in environments where storing secrets securely is difficult; PKCE doesn't authenticate the client itself, but it stops attackers from weaponizing an intercepted authorization code — https://aembit.io/blog/mcp-oauth-2-1-pkce-and-the-future-of-ai-authorization/. Its protection still depends on the authorization server correctly validating code_verifier; misconfiguration leaves code-interception attacks possible (modelcontextprotocol.io/specification/draft/basic/authorization).

Token scoping and per-tool permissions: the checklist for a server build

This is the part a builder implements directly, per the spec (modelcontextprotocol.io/specification/draft/basic/authorization):

- Resource Indicators (RFC 8707) are mandatory in both the authorization request and the token request — MCP clients MUST implement them, so a token is scoped to one specific MCP server and cannot be replayed against another. - MCP servers MUST validate that the access token's audience matches them specifically, per RFC 8707 §2 — accepting a token issued for a different resource is the bug that opens the confused-deputy hole below. - When a token lacks the required permission, the server SHOULD respond HTTP 403 Forbidden with a WWW-Authenticate header carrying error="insufficient_scope" (and SHOULD include the required scope in that header) so the client can trigger a step-up authorization flow. - Scopes should be granular and function-specific — e.g. files:read, email:send, contacts:read — rather than one broad catch-all, checked at every tool invocation, not once at connection time — https://www.redhat.com/en/blog/mcp-security-implementing-robust-authentication-and-authorization. The spec itself does not mandate per-tool or per-resource granularity: it only requires scope guidance in 401/403 responses, leaving actual enforcement to the server implementation (modelcontextprotocol.io/specification/draft/basic/authorization) — this is the concrete gap a builder must close in application code. See Building an MCP Server: SDKs, Tool Schemas, Testing, and Deployment — the practical path from a 15-minute local prototype to a hosted remote server for where this fits into the server build itself, and MCP Limits: Confused Deputy and Overbroad Permission Scopes — why a server you built safely can still act with someone else's authority for the failure mode when it is skipped. - Token lifetimes for AI agents should be short — 5 to 15 minutes — with real-time revocation, because an agent can operate continuously and silently, so a compromised long-lived token is worse than a compromised long-lived human session — https://www.scalekit.com/blog/delegated-agent-access.

Confused deputy and the On-Behalf-Of fix

if an MCP server passes the caller's token straight through to a downstream service, the server becomes a "confused deputy" — tricked into using its elevated authority for someone who does not actually hold it — https://www.flowhunt.io/blog/mcp-authentication-authorization-oauth-confused-deputy/. The On-Behalf-Of (OBO) flow mitigates this: the MCP server exchanges the user's token for its own explicitly-scoped server token before calling downstream, so user and server permissions never get conflated (same source). Delegated tokens should also carry both identities via JWT sub (agent) and act.sub (acting-user) claims, for attribution and least-privilege enforcement across the chain — https://dev.to/stacklok/token-delegation-and-mcp-server-orchestration-for-multi-user-ai-systems-3gbi.

Gateway pattern

the emerging dominant enterprise architecture puts a dedicated component between clients and servers that intercepts every request to apply context-aware authorization policy, centralizing enforcement, transforming tokens to reduce exposure, and creating an audit boundary — https://blog.gitguardian.com/oauth-for-mcp-emerging-enterprise-patterns-for-agent-authorization/. See Enterprise MCP Integration Patterns — the Gateway Layer and the Build-vs-Buy Call Before You Ship a Server for this pattern at the deployment level.

Enterprise-Managed Authorization (stable extension, July 2026)

Repeated per-server consent prompts were reported as one of the biggest connectivity-management pain points in enterprise environments — https://www.infoq.com/news/2026/07/mcp-ema-enterprise-auth/. In July 2026 the MCP team promoted Enterprise-Managed Authorization (EMA) from proposal to stable extension status to address this (same source). EMA uses Identity Assertion JWT Authorization Grant (ID-JAG) tokens: the client obtains a JWT from the identity provider during single sign-on and exchanges it for an MCP access token without an interactive per-server consent screen — modelcontextprotocol.io/extensions/auth/enterprise-managed-authorization. Under EMA, the organization's IdP (e.g. Okta, Azure AD) becomes the authoritative decision-maker: employees authenticate once with their normal corporate credentials, and the IdP grants or denies access to each configured MCP server based on group membership, role assignment, and conditional-access policy (same source) — eliminating the per-server, per-user authorization flow described above.

What does NOT work / open problems

- Token passthrough (forwarding the caller's token unchanged to a downstream service) creates the confused-deputy vulnerability described above — it is a known anti-pattern, not a shortcut — https://www.flowhunt.io/blog/mcp-authentication-authorization-oauth-confused-deputy/. - Consent UX is unresolved (UNVERIFIED beyond the spec's own note): the spec observes that MCP clients are general-purpose and "typically lack domain-specific knowledge to make informed decisions about individual scope selection," and notes that some deployments cope by requesting *all* available scopes up front during initial consent — a workaround that undercuts least-privilege in practice (modelcontextprotocol.io/specification/draft/basic/authorization). - Dynamic Client Registration security is unspecified: the spec lists RFC 7591 support as optional (MAY, not MUST) and does not mandate how an authorization server should secure its registration endpoint (e.g. registration-endpoint authentication, client-assertion validation) — a gap left to each implementation. - Token leakage remains an open risk when tokens are stored in plaintext, logged to files, or leaked in error messages; mitigation is short-lived tokens with refresh-token rotation plus revocation detection via JWT introspection — https://www.redhat.com/en/blog/mcp-security-implementing-robust-authentication-and-authorization. - Per-tool enforcement granularity is not standardized: as noted above, the spec stops at recommending scope hints in error responses; there is no normative per-tool permission model, so two compliant servers can implement wildly different actual enforcement.

Related

- MCP Transports: stdio for Local Servers, Streamable HTTP for Remote Ones — why this whole model applies only to remote (HTTP) servers and explicitly not to local stdio servers. - Building an MCP Server: SDKs, Tool Schemas, Testing, and Deployment — the practical path from a 15-minute local prototype to a hosted remote server — where token validation, scope checks, and 403/step-up handling actually get written into server code; this page supplies the exact spec requirements that code must satisfy. - MCP Limits: Confused Deputy and Overbroad Permission Scopes — why a server you built safely can still act with someone else's authority — the concrete failure mode (token passthrough, overbroad scopes) that RFC 8707 audience validation and the OBO flow exist to close. - Enterprise MCP Integration Patterns — the Gateway Layer and the Build-vs-Buy Call Before You Ship a Server — the gateway/proxy deployment shape that operationalizes centralized authorization at scale, and where Enterprise-Managed Authorization fits organizationally. - MCP Adoption and the July 2026 Spec — what changed under you while you weren't looking — the July 2026 spec release candidate that carries this "refreshed auth" forward alongside the stateless-core and Tasks/Apps extensions.

Verified against

Source: Sinapsi — verified compositional memory, queryable by LLMs. Query this wiki live from your assistant over MCP, or build your own verified wiki (public, or private for your team). CC BY 4.0 — reuse with attribution to Sinapsi.