Learning · Updated 2026-07-19 · 9 min
OAuth 2.1 PKCE for remote MCP agents
A practical security model for authorizing remote MCP clients with OAuth 2.1, PKCE, resource discovery, and least-privilege tokens.
intermediate · 7 sources · Prerequisites: HTTP APIs, bearer tokens, basic OAuth roles
OAuth 2.1 PKCE for remote MCP agents
Why this matters
Remote MCP changes the trust boundary. A local STDIO MCP server can often inherit credentials from the user's machine, but an HTTP-based remote MCP server is a network protected resource: it needs a way to let an agent act for a resource owner without giving the agent the user's password or a permanent all-powerful API key. The MCP authorization specification therefore defines an optional authorization layer for HTTP transports and says STDIO transports should not use that flow; STDIO should retrieve credentials from the environment instead [S001].
The core design is OAuth delegation, not agent identity magic. OAuth 2.1 lets a client obtain limited access to a protected resource with resource-owner approval; the client then uses an access token rather than the user's credentials [S002]. In MCP terms, the protected MCP server is the OAuth resource server, the MCP client is the OAuth client, and the authorization server issues the token that the MCP server accepts [S001].
Mental model
Think of remote MCP authorization as five separable contracts:
- Resource discovery: the MCP server tells an unauthenticated client where its protected-resource metadata lives. MCP servers must support either a
WWW-Authenticatechallenge containingresource_metadataor a well-known protected-resource metadata URL; MCP clients must support both discovery mechanisms [S001]. RFC 9728 is the underlying standard for protected resource metadata and defines metadata that clients or authorization servers can use to learn how to interact with a protected resource [S004]. - Authorization-server discovery: protected-resource metadata points to the authorization server or servers. Authorization server metadata then publishes endpoint locations and capabilities, such as authorization and token endpoints [S005].
- Client registration: the authorization server needs to know what client is asking. MCP allows pre-registration, dynamic client registration, and client ID metadata documents; dynamic registration is the OAuth mechanism for submitting client metadata and receiving a client identifier [S001][S006].
- User-delegated authorization with PKCE: a public MCP client initiates an authorization-code flow with a PKCE code challenge, then redeems the returned authorization code with the matching code verifier [S002][S003]. PKCE mitigates authorization-code interception because a stolen code is not enough; the attacker also needs the verifier generated by the legitimate client [S003].
- Resource-bound token use: where supported, the client should identify the intended protected resource, and the authorization server can restrict the token audience so that a token issued for one MCP server cannot be replayed at another [S007].
The useful slogan is: discover the resource, discover the issuer, register or identify the client, authorize with PKCE, then use an audience-restricted bearer token only at the intended MCP server.
The trust boundary is visible here: the agent never receives the user's password, and the resource server remains the final policy enforcement point.
The flow in practice
A typical remote-agent flow looks like this:
- The agent's MCP client calls the remote MCP endpoint without a token.
- The MCP server returns
401 Unauthorizedand includes enough metadata discovery information for the client to find protected-resource metadata [S001][S004]. - The client fetches protected-resource metadata and extracts authorization server information [S001][S004].
- The client fetches authorization server metadata to learn the authorization endpoint, token endpoint, supported grant types, and supported PKCE methods [S005].
- If the client is not already known to the authorization server, it registers metadata and receives a client identifier, or it uses a supported client ID metadata document mechanism [S001][S006].
- The client opens a browser or equivalent user-agent authorization interaction with an authorization request that includes
code_challengeandcode_challenge_method=S256[S002][S003]. - After the resource owner approves, the authorization server redirects back with an authorization code.
- The client redeems the code at the token endpoint with the original
code_verifier; the authorization server verifies the PKCE binding before returning tokens [S003]. - The client calls the MCP server with the access token. The MCP server validates the token issuer, audience, expiration, scope, and any local policy before executing tools or returning resources [S001][S007].
This is intentionally more ceremony than a static API key. The payoff is revocation, consent, scoped access, token lifetime control, and separation between the agent, the MCP server, and the identity provider.
Trade-offs
OAuth 2.1 plus PKCE gives remote agents a standard browser-mediated consent path, but it does not by itself prove that a local desktop app or CLI is the human-intended client. Public clients cannot keep a client secret, so PKCE protects the code exchange while client identity still depends on redirect URI policy, client registration policy, metadata validation, and user-visible consent [S003][S006].
Dynamic client registration improves interoperability because arbitrary MCP clients can connect without manual pre-provisioning, but it expands the attack surface. A permissive authorization server can be tricked into registering confusing names, misleading logos, broad redirect URIs, or clients that request excessive scopes. Registration policy is therefore a security control, not just developer experience plumbing [S006].
Protected-resource metadata reduces hard-coded configuration and supports multi-issuer deployments, but clients must treat fetched metadata as security-sensitive input. Metadata discovery should use HTTPS, strict URL validation, issuer checks, SSRF defenses, and cache invalidation rules; otherwise an attacker who influences discovery can route the client toward the wrong authorization server [S004][S005].
Resource indicators and audience-restricted tokens are especially important for agent ecosystems. Agents often connect to many tools. If every tool receives a generic bearer token, one compromised server can become a confused deputy for another. Resource indicators let the client tell the authorization server where the token will be used, enabling narrower audiences [S007].
Failure modes
- Treating PKCE as client authentication. PKCE proves continuity between the authorization request and token request; it does not make a public client confidential or uniquely trustworthy [S003].
- Accepting tokens without audience validation. A token minted for a different MCP server should not authorize this MCP server; otherwise token redirection and confused-deputy failures are likely [S007].
- Hard-coding a single authorization server when the MCP resource publishes metadata. Hard-coding can work for a private deployment, but it defeats the discovery and interoperability model [S001][S004][S005].
- Over-broad scopes for agents. Remote agents can chain tool calls quickly; default scopes should be minimal and step-up authorization should be used for sensitive operations [S001].
- Unsafe dynamic registration. Letting any client register any redirect URI, logo, or name without validation enables phishing, authorization-code capture, or user confusion [S006].
- Long-lived bearer tokens in agent logs. OAuth reduces password sharing, but bearer tokens are still secrets. Agents must avoid logging, prompt-injecting, or storing them in durable memory [S002].
This turns the failure list into an operational checklist: every request must survive issuer, audience, lifetime, and scope checks before a tool runs.
Worked example
Suppose a hosted MCP server exposes calendar and document tools for a team. A remote desktop agent wants to call calendar.search and later maybe docs.write.
A safe baseline is:
- The MCP server exposes protected-resource metadata and lists an authorization server controlled by the organization [S001][S004].
- The authorization server publishes metadata, supports authorization code plus PKCE, and advertises the relevant token endpoint and PKCE challenge methods [S005].
- The desktop MCP client is a public client. It uses PKCE with S256 and a loopback or custom-scheme redirect URI that matches registration policy [S002][S003][S006].
- The initial request asks only for read-only calendar scope. When the agent attempts
docs.write, the MCP server returns an insufficient-scope challenge and the client performs step-up authorization rather than silently escalating [S001]. - Tokens are audience-bound to the calendar/docs MCP resource, not reusable at unrelated APIs [S007].
The decision point is not “OAuth or API key?” It is “Which authorization server, client registration policy, scopes, token lifetime, and token audience rules make this agent safe enough for the tools it can invoke?”
What I would do
For a production remote MCP server, I would implement the MCP authorization profile on top of an existing OAuth/OIDC provider rather than invent a new token issuer. I would require authorization code with PKCE for user-delegated clients, publish protected-resource metadata, consume authorization server metadata, validate token issuer and audience, and start with narrow scopes. I would allow dynamic registration only behind a policy layer that validates redirect URIs, client metadata, and requested scopes [S001][S003][S004][S005][S006][S007].
For internal-only agents, I would still prefer OAuth when users delegate access to personal or team resources. A static service token is acceptable only for non-user-specific backend automation with tightly bounded tool permissions, strong secret handling, and no need for end-user consent or revocation.
Speculation and open questions
The hard unsolved part is not PKCE; it is user comprehension and client trust. Agent clients may request access on behalf of complex plans the user does not fully understand. Future MCP deployments will likely need richer consent screens, tool-level scopes, authorization-server risk signals, and runtime step-up prompts that explain concrete agent actions rather than abstract API scopes.
Sources
- [S001] Authorization - Model Context Protocol.
- [S002] The OAuth 2.1 Authorization Framework.
- [S003] Proof Key for Code Exchange by OAuth Public Clients.
- [S004] OAuth 2.0 Protected Resource Metadata.
- [S005] OAuth 2.0 Authorization Server Metadata.
- [S006] OAuth 2.0 Dynamic Client Registration Protocol.
- [S007] Resource Indicators for OAuth 2.0.