An employee might ask an AI assistant to summarize the week’s sales, while a scheduled agent creates that same summary every morning before anyone logs in. Both use the same tool on the same MCP server. Both agents can look almost identical to the server, but they shouldn’t have the same identity or authority.
The assistant works on behalf of a person, so its access should stop where that person’s access stops. The scheduled agent doesn’t have a person behind it, so it needs its own identity. A third version, used by thousands of employees, might need to follow rules set by the company’s identity provider instead of relying on each employee’s choices on a consent screen.
Authorization protocols are designed to handle these differences. When I first wrote about MCP authorization in May 2025, the protocol used OAuth 2.1 and Proof Key for Code Exchange (PKCE), but it didn’t fully address clients without a person behind them. The MCP 2026-07-28 specification improves on this by making discovery and token validation stricter and adding options for unattended agents and centrally managed access.
The central conclusion still stands: Authorization depends on identity. MCP now gives builders better ways to carry identity into authorization flows and clearer points at which to enforce policy.
Three Patterns of MCP Authorization
MCP authorization is optional and applies to HTTP-based transports. Implementations that use stdio get credentials from their environment instead. The roles are the same as in OAuth: the MCP server protects something valuable, the client requests access, and an authorization server decides whether to grant access and issue a token.
A major structural change affects everything else: MCP no longer uses protocol-level sessions. The old initialize handshake and Mcp-Session-Id header are gone. Now, each request is independent, including its protocol version, client identity, and capabilities in a _metafield. Authorization is included with every request instead of being set once and reused.
Within that model, three general patterns emerge:
- User-delegated access: The client acts on behalf of a person, using an Authorization Code with PKCE and an approval step.
- Machine-to-machine access: An unattended client acts on its own behalf, using the optional OAuth Client Credentials extension to authenticate without a browser or user.
- Enterprise-managed access: A person still operates the client, but the organization decides which servers and scopes are available, through the optional Enterprise-Managed Authorization extension.
OAuth 2.1 and PKCE Anchor Delegated Access
OAuth 2.1 is still an active Internet-Draft. Revision 15 was released in March 2026, and the working group plans to submit it to the IESG in December. MCP uses revision 13 as its reference. OAuth 2.1 combines the original OAuth 2.0 framework with 10 years of security updates into a single draft. MCP relies most on PKCE.
PKCE stops anyone who intercepts an authorization code from using it. The client creates a random secret called the code_verifier and sends only a hash of it, the code_challenge, with its authorization request. When redeeming the code, the client presents the real secret. The authorization server issues tokens only if hashing the secret matches the original challenge. The secret is sent only in the client’s direct call to the token endpoint, so it never appears in the browser redirect where codes are most at risk. MCP requires the stronger S256 hashing method whenever possible.
This revision also fixes a less obvious weakness. Neither OAuth 2.1 nor PKCE defines a way for a client to discover whether an authorization server supports PKCE, so MCP requires clients to check for code_challenge_methods_supported in that server’s metadata and stop if it is missing.
All of this protects the exchange, which is especially important for public clients, such as desktop apps or CLI tools, that can’t keep secrets. However, it doesn’t address the software that holds the verifier.
One Token Per MCP Server
The flow begins with OAuth 2.0 Protected Resource Metadata, or PRM, which protected MCP servers must publish. A client arriving without a valid token gets a challenge telling it where to look:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer
resource_metadata="https://mcp.example.com/.well-known/oauth-protected-resource", scope="tools:generate_summary
The document at that address names the resource, the authorization servers that can issue tokens for it, and the scopes it supports. From there, the client works through a stricter sequence than before:
sequenceDiagram
participant U as User's browser
participant C as MCP client
participant M as MCP server
participant A as Authorization server
C->>M: tools/call, no token
M-->>C: 401 with resource_metadata and scope
C->>M: Fetch protected resource metadata
M-->>C: Resource, authorization servers, scopes
C->>A: Fetch authorization server metadata
A-->>C: Issuer, endpoints, PKCE support
Note over C: Record issuer, generate PKCE verifier,<br/>obtain client ID
C->>U: Authorization request with code_challenge and resource
U->>A: User authenticates and approves
A-->>U: Authorization code and iss
U-->>C: Authorization code and iss
Note over C: Compare iss to recorded issuer
C->>A: Token request with code_verifier and resource
A-->>C: Access token for this MCP server
C->>M: tools/call with Bearer token
Note over M: Validate audience, lifetime, scopes
M-->>C: Tool result
Three parts of that sequence are stricter than before. The client records the authorization server’s issuer identity up front and compares it to the iss value returned before redeeming its code, as required by RFC 9207. This prevents a hostile authorization server from passing off someone else’s response as its own. The client gets a client ID by preferring pre-registered credentials, then a Client ID Metadata Document (CIMD), and only then Dynamic Client Registration, which this revision of the MCP spec deprecates but keeps for compatibility. It also includes a resource indicator in both requests, so the token is tied to a single MCP server rather than being usable anywhere.
The audience rule is important to remember. A token issued for one service should not work as a general-purpose key. Servers should accept only tokens issued for them, and clients should never pass a token received for one service to another. This becomes especially important in a chain: if an MCP server calls upstream APIs, it acts as a client and needs its own token. Otherwise, the intermediary could become a confused deputy—a service that holds more authority than its caller is entitled to, and that can be tricked into performing actions on the caller’s behalf.
Scopes can also change during a session. If a tool call requires more authority than the token has, the server replies with 403 Forbidden and an insufficient_scope challenge explaining what is needed. A user-delegated client can then request those scopes along with the ones it already has.
The Challenge of Software Identity Verification
A user can authenticate and approve scopes, and PKCE can link the authorization code to the flow that started it. However, nothing in this process tells the server which program is actually making the request.
The stateless design makes this gap harder to close because the server cannot rely on a previously established session or connection when evaluating a request. Every request announces its client’s name, version, and capabilities in _meta, but this information is self-asserted, and a malicious process can claim to be a familiar client application just as a legitimate one can. For clients that people use, policy needs both parts: who the user is and which agent they are operating. For autonomous agents, the question is about non-human identity: which agent may hold a token, where it runs, and under what conditions.
Autonomous Agents Need an Identity of Their Own
The scheduled agent I mentioned at the beginning of this article now has a standard path. The OAuth Client Credentials extension lets an autonomous agent, background service, or CI/CD job authenticate directly with the authorization server and get a token without user intervention. This extension is still a draft in MCP’s extensions repository, so details may change.
The extension accepts a client ID and secret but recommends using a signed assertion instead. Following RFC 7523, the client signs a short-lived JWT with its private key, naming itself in the iss and sub fields and the token endpoint in the aud field. The authorization server checks that signature against the public key it has on file. The private key stays with the client, and the assertion expires within minutes instead of sitting in a configuration file until someone rotates it.
This is real progress, but it moves the identity problem rather than solving it, because secrets can be copied, private keys can be stolen, and registration records only show that a credential belongs to a client. Stronger identity requires evidence from the infrastructure itself. Depending on the environment, that evidence might include cloud workload identity tokens, Kubernetes service account tokens, signed executables, or deployment attributes. Authorization servers and workload identity platforms must map those signals to an approved agent. MCP defines the token exchange but leaves that infrastructure-specific mapping outside the protocol.
sequenceDiagram
participant R as Cloud or Kubernetes runtime
participant C as Autonomous agent
participant A as Authorization server
participant M as MCP server
C->>R: Request runtime identity token
R-->>C: Signed token attesting where the agent runs
C->>A: Token request: signed JWT assertion plus runtime evidence
Note over A: Verify assertion signature,<br/>evaluate runtime evidence and policy
A-->>C: Short-lived access token
C->>M: tools/call with Bearer token
Note over M: Validate audience, lifetime, scopes
M-->>C: Tool result
MCP defines the signed assertion in that exchange. The runtime evidence above it sits outside the specification, which is why it varies by environment.
Enterprise-Managed Access Starts at the Identity Provider
Consent screens are helpful when one person decides which app can read their data. At company scale, though, per-user approvals make access inconsistent, revocation scattered, and audit trails incomplete.
The Enterprise-Managed Authorization (EMA) extension moves this decision to the company’s identity provider. An employee signs in to the MCP client with their corporate credentials, and the client keeps the resulting assertion, which is an OpenID Connect ID token or a SAML assertion. The identity provider evaluates the organization’s policies—such as group membership, role, conditional access, and approved servers—and, if the request is allowed, issues an Identity Assertion JWT Authorization Grant (ID-JAG). The client sends that short-lived signed grant to the MCP authorization server, which exchanges it for an access token for the target server. Because the organization has already made the access decision, the employee does not see an individual consent screen.
sequenceDiagram
participant U as Employee's browser
participant C as MCP client
participant I as Enterprise identity provider
participant A as MCP authorization server
participant M as MCP server
U->>I: Corporate sign-in
I-->>C: ID token or SAML assertion
C->>I: Exchange assertion for ID-JAG naming the target resource
Note over I: Evaluate group, role, conditional access,<br/>approved MCP servers
I-->>C: ID-JAG
C->>A: Token request with ID-JAG
Note over A: Validate ID-JAG signature, issuer, audience
A-->>C: Access token for this MCP server
C->>M: tools/call with Bearer token
M-->>C: Tool result
Since the identity provider issues the grant, it can consider group membership, role, conditional access rules, and its own list of approved MCP servers before giving out any token. Employees without authorization get an error instead of a token, and administrators can manage everything from one console.
EMA settles how organizational policy and user identity enter the flow, but not agent identity. Both it and the Client Credentials extension are negotiated rather than assumed: clients declare them with each request, servers advertise them in the optional server/discover response, and neither is ever on by default. EMA is the more mature of the two, published as stable while Client Credentials is still a draft, though client support for both varies.
Each Request Carries Its Own Authorization
With no session to set up, any request can go to any instance behind a regular load balancer, and each request carries its own authorization. Streamable HTTP requests now include the required Mcp-Method and Mcp-Name headers, which indicate the operation and tool name, allowing a gateway or policy engine to read them without parsing the JSON body. This makes it practical to enforce policy on each request. Something in the path can authorize each tool call on its own terms and log the decision, rather than relying on a session approved earlier.
What MCP Builders Should Do Now
- Decide whether each client is user-delegated, machine-to-machine, or enterprise-managed before picking a flow.
- Discover endpoints through PRM and authorization server metadata rather than hardcoding them.
- Use Authorization Code with PKCE and
S256; refuse to continue if the server doesn’t advertise PKCE support; and validate redirect URIs, state, and the response issuer. - Prefer CIMD over dynamic registration, and file every other credential under the issuer that granted it.
- Bind tokens with the
resourceparameter, validate audience and scope on every request, and don’t forward a token you received. - For unattended clients, prefer signed JWT assertions over reusable secrets, and tie those credentials to verified runtime identity.
- Keep tokens short-lived, rotate refresh tokens for public clients, protect signing keys, and treat extensions as capabilities both sides advertised.
Overall, the stricter discovery rules, token binding, and new extensions give MCP a stronger foundation than it had a year ago. They also make it easier to see where the remaining gaps are.
Authorization answers what a client may access. Identity answers which user, agent, and runtime are making the request. Agentic systems need both, but the protocol describes only the first.
At Aembit, this means verifying an AI agent’s non-human identity and considering it along with the user and runtime context when those signals are available. It also means brokering downstream credentials so the agent does not have keys to every MCP server it accesses, which helps solve the confused deputy problem. Aembit checks the agent’s token on every request and evaluates client-to-gateway and gateway-to-server policy as separate decisions. It then fetches the credentials needed for the target MCP server and records the agent, user, target, and decision for each call.
MCP now provides more of the needed tools. Builders still need to connect it to a verifiable identity and an access policy they can enforce.