OAuth 2.1 with PKCE is now the mandatory best practice for securing agent tool invocation and orchestration with MCP (Model Context Protocol), providing protection against authorization code interception while enabling secure, scalable client registration and token issuance for agentic AI systems
This blog post give more context about this approach.
Why MCP Servers Must Leverage PKCE
Agentic AI clients in MCP typically run in dynamic, ephemeral, or containerized environments where:
The attack surface is broader. Agents communicate with multiple distributed services, increasing interception risks.
Accountability and trust granularity are crucial. Agents can perform sensitive automated actions, so authorization must be tightly bound and verifiable.
PKCE provides an effective solution by:
Protecting the authorization code exchange step, a known attack vector in traditional OAuth flows.
Ensuring that intercepted authorization codes are useless without the client-generated code verifier secret.
Allowing public clients (like MCP agents) to securely perform authorization code flow without the need for confidential client secrets.
Reducing the risk window by enabling short-lived tokens and secure renewals combined with PKCE.
This security enhancement is particularly important when agents act autonomously across systems, as any unauthorized access can escalate quickly if tokens are stolen.
The Sequence Diagram
The following figure is a simplified 7 step sequence diagram to show how PKCE works in MCP client and server interaction.
Step 1: Client Generates PKCE Secrets
Before starting the authorization, the MCP client (such as an agent) generates a random secret string (one time use and needs to generate again if used) called the code_verifier. It then derives a hashed version called the code_challenge using SHA-256. This challenge will be sent to the authorization server during the authorization request. The verifier remains secret to the client.
Step 2: Authorization Request to IDP
When the user initiates login or consent, the client sends an authorization request to the dedicated Identity Provider (IDP). This request includes essential parameters like client ID, redirect URI, scopes, and importantly the code_challenge and code_challenge method (S256 indicating SHA-256 hashing).
Step 3: User Authentication and Consent
The IDP prompts the user to authenticate (login) and consent to the requested permissions. This is the typical OAuth authorization prompt flow where the user explicitly grants access consent to the client.
Step 4: Authorization Code Issued
Once the user approves and authenticates, the IDP responds by redirecting the user-agent back to the client’s redirect URI with an authorization code included in the URL. This code is a temporary token representing this authorization.
Step 5: Token Request with Code Verifier
The client now makes a secure request to the IDP token endpoint to exchange the authorization code for tokens (access, ID, refresh tokens). Along with the authorization code, the client sends the one time use code_verifier secret it generated.
Step 6: PKCE Validation by IDP
The IDP hashes the provided code_verifier and compares it to the original code_challenge received during authorization. If the verification succeeds, meaning the client redeeming the code is the same that requested authorization, the server issues the tokens. Otherwise, it rejects the request.
Step 7: Access Tokens Used to Call MCP Server APIs
Armed with the access token, the client makes authenticated requests to the MCP server (the protected resource server). The MCP server validates the tokens and authorizes access to protected APIs or data.
How MCP Server Can Implement PKCE
The MCP authorization specification explicitly requires MCP clients to implement PKCE according to OAuth 2.1 Section 7.5.2 for avoiding authorization code interception and injection attacks.
An example PKCE flow in MCP might look like:
Agent (MCP client) generates a code_verifier during authorization request.
It derives a code_challenge and sends it with the authorization request.
The MCP authorization server saves the challenge and issues an authorization code after user consent or agent approval.
The agent redeems the code by presenting the original code_verifier.
The server verifies the code challenge integrity and issues tokens.
Tokens are used to access MCP server APIs securely.
Key Implementation Points for MCP Servers:
Enforce S256 code challenge method—the more secure SHA-256 variant over the plain method.
Require exact redirect URI matching during registration and requests.
Validate PKCE support metadata so clients only proceed if the authorization server supports PKCE.
Log and audit PKCE token exchanges to detect suspicious activity.
Ensure short-lived access tokens and rotating refresh tokens to limit impact from token compromise.
Dedicated IDP Integration with MCP Servers
While MCP specification defines how clients obtain and present tokens securely via OAuth and PKCE, MCP servers should rely on dedicated Identity Providers (IDPs) for handling authentication, authorization, and token issuance.
Using a dedicated IDP provides security, scalability, and compliance benefits, such as:
Centralized user and client authentication policies.
Robust token validation including JWT signature verification and revocation.
Scalable token issuance and management infrastructure.
Integration with enterprise SSO or multi-factor authentication.
1. Standalone IDP with OAuth 2.1 + PKCE Support
The MCP server delegates authentication to an OAuth 2.1-compliant IDP.
IDP supports PKCE for client authorization code flow.
MCP server validates tokens issued by this IDP using JWT signatures and token introspection.
Examples: Microsoft Identity Platform, Auth0, Okta.
2. IDP Federation or Broker Model
MCP server delegates to an IDP broker that federates with multiple upstream IDPs.
Supports authentication via corporate SSO, social providers, or other federated systems.
PKCE is supported at the authorization code flow level for client sessions.
Ensures broad compatibility and consolidated identity management.
3. Embedded Minimal IDP + Token Validation
For lightweight or internal deployments, MCP servers may embed minimal IDP functionality implementing OAuth 2.1 + PKCE flows.
Suitable for controlled environments with limited scale.
Full token validation logic to ensure compliance with PKCE and OAuth standards is critical.
Why Use a Dedicated IDP for MCP?
Separation of Concerns: MCP servers focus on authorization enforcement and API-level access control, delegating complex user/client authentication to IDPs.
Security: IDPs implement hardened security controls, including rate limiting, anomaly detection, credential management, and revocation.
Compliance: IDPs often provide compliance with GDPR, HIPAA, SOC2, etc., meeting enterprise requirements.
Developer Productivity: Leverages existing OAuth/OIDC standards and libraries, simplifying MCP server implementation.
Token Lifecycle Management: Handles refresh tokens, revocation, and secure key rotations transparently.
Summary
PKCE is needed for MCP servers for securing the authorization code flow against interception and replay attacks in agentic AI environments. MCP’s reliance on ephemeral, stateless clients without secure secret storage makes PKCE a mandatory defense.
Incorporating a dedicated OAuth 2.1-compliant IDP that supports PKCE provides secure issuance and validation of tokens, streamlines identity management, and enhances compliance and scalability.
Whether through standalone IDPs, federated brokers, or embedded implementations, MCP server developers must prioritize PKCE-enabled OAuth flows to maintain security, trust, and control in autonomous AI agent ecosystems.
This approach ensures MCP-based agentic systems are robust against emerging security threats intrinsic to dynamic, AI-driven automation.
If you are developing or architecting MCP servers, consider how PKCE fits into your OAuth flows and plan integration with trusted IDPs early to build secure agent authorization from the ground up.
"Storing secrets securely is difficult or impossible" -- your assumption is incorrect--it's not impossible. "Difficult"... what does that even mean? Anything unfamiliar is "difficult"--but OAuth is not rocket science.
Note: I'm not arguing against the use of PKCE. It's good security hygiene. In some ways, it's complimentary to checking the "state" in OAuth, or the "nonce" in an id_token. For example, the nonce in an id_token is verified by the client to make sure the response is bound to a specific authn request. PKCE is used by the server to ensure the token request comes from the same client that started the flow. This is all good stuff.
But don't fall into the trap of thinking that PKCE in any way abolves you from cryptographically identifying the client, and the benefits that accrue when you do so. For example, in your audit log, do you want to say "a client" or "this specific client" performed an action on a resource?
The fact that we can't centrally generate a shared secret (e.g. client_id + client_secret) or a private key on the server is correct. But there are certainly lots of other cases where we face the same challenge and find a solution to enable a client to avoid shared secrets.
Ultimately, what you are doing is passing on the trust model for security. This is the same mistake that got us in the bad security situation we are in today.