Est.

MCP OAuth and Credential Handling Fundamentals

Most MCP servers still use static keys instead of OAuth, creating widespread security risk.

Features Editor · · 12 min read
Cover illustration for “MCP OAuth and Credential Handling Fundamentals”
Agentic AI Foundations · September 1, 2026 · 12 min read · 2,743 words

MCP has become the default way AI agents connect to enterprise systems. Anthropic, OpenAI, Google, and Microsoft are all building support for it, which means agents now read databases, call APIs, write to SaaS platforms, and chain actions across tools that were never built to talk to each other. Getting authentication right, meaning how an agent proves who it is and how long its access lasts, is what separates a deployment that works from one that quietly turns into a liability. Most MCP servers running today get this wrong, and not by a narrow margin either. The wrong way outnumbers the right way by a wide margin, and that gap is the actual story here.

Early MCP deployments left authentication almost entirely up to whoever was building the server. There was no required model, so teams improvised, and the result was a mess. Astrix Security's "State of MCP Server Security 2025" study looked at more than 5,000 open-source MCP servers and found 53% relying on static API keys or personal access tokens: credentials that live forever, rarely get rotated, and leak more often than anyone wants to admit. Only 8.5% of those servers had adopted OAuth by the time the study ran. By early 2026, roughly half of nearly 7,000 internet-exposed MCP servers had no authentication controls at all.

That pattern traces back to a spec that didn't pick a lane on authentication early. The June 2025 and November 2025 updates settle on OAuth 2.1, close the gaps that let teams improvise their way into trouble, and make the safe path the one that takes the least effort to follow.

Diagram: Static Keys vs. OAuth: The Authentication Gap in MCP Servers Today. Visualizes: Visualize the stark authentication disparity across more than 5,000 open-source MCP servers studied by Astrix Security in 2025.

How the June 2025 spec settled the authorization server question

Before June 2025, a real question sat underneath every MCP deployment: should the MCP server issue its own tokens, or hand that job to something else? The spec answered it, and the answer wasn't close. MCP servers are OAuth 2.0 Resource Servers, full stop. Their only job is to validate tokens that some other, separate authorization server already issued. They don't mint credentials, and any team that tries to build its own token issuance on top of MCP is fighting the spec, a fight that ends badly more often than not.

That distinction changes how the whole system gets built. The actual authority, the system that knows who a user is and what they're allowed to do, stays with the identity provider the organization already runs. MCP servers plug into that IdP rather than standing up a competing one.

So how does a client know which authorization server to talk to? Through Protected Resource Metadata, defined in RFC 9728. When a request needs authorization, the MCP server returns an HTTP 401 along with a WWW-Authenticate header that points to a resource_metadata URL. That URL leads to a PRM document, and inside it sits an authorization_servers field, the list of places a client can go to get a token. If more than one authorization server is listed, picking the right one is on the client.

Resource Indicators, from RFC 8707, add a second layer. They bind a token to the specific resource it was issued for, so a token minted for one MCP server can't get replayed against a different one. Authorization servers, for their part, have to expose at least one discovery mechanism, either standard OAuth 2.0 metadata or OIDC discovery, so clients aren't guessing at endpoints.

Put together, this lets an organization run MCP access through the identity stack it already governs. No side door, no shadow identity system sitting outside the reach of whoever manages access company-wide.

What PKCE does and why the spec treats it as non-negotiable

PKCE, short for Proof Key for Code Exchange, is required for every public remote MCP server under the spec. No exceptions for internal tools, none for "trusted" networks. HTTPS on every endpoint carries the same weight.

Mechanically, it works like this: before the client sends an authorization request, it generates a random code_verifier. It hashes that value into a code_challenge and sends the hash along with the request. Later, when the client trades its authorization code for an actual token, it has to send back the original, unhashed code_verifier, and the server checks that the hash lines up. If an attacker intercepts the authorization code somewhere in transit, that code is dead on arrival, because the attacker doesn't have the matching verifier.

That's what PKCE stops: someone grabbing an authorization code mid-flight and using it themselves. PKCE tells the server the code wasn't stolen; it says nothing about whether the party presenting it is legitimate, and treating it as a full identity check is a mistake worth naming plainly. It's a lock on one specific door, not a guard checking IDs.

The OAuth state parameter fills a different gap, and the spec requires it too. It has to be a random value, stored in the client's session before the redirect happens, then checked again when the callback comes in. Skip this step and an attacker can craft a link that hands their own authorization code to a victim's session, a session fixation attack. This exact hole showed up in real MCP implementations during 2025.

CVE-2025-6514 shows what happens when these protections aren't enforced. It hit the mcp-remote proxy package across more than 437,000 installed environments and carried a CVSS score of 9.6, one of the worst vulnerabilities the MCP ecosystem has seen. The proxy trusted whatever OAuth endpoints a server handed it, no questions asked. A malicious server could return an authorization_endpoint value containing a shell command, and the proxy passed that string straight into the system shell, giving an attacker arbitrary command execution with the victim's own privileges. The root cause traced back to one missed step: nobody checked the metadata the spec already says servers must advertise and clients must verify.

How the November 2025 spec addressed runtime permission gaps with incremental scopes and step-up authorization

Front-loading every permission an agent might ever need, right at connection time, leaves agents holding tokens with far more access than any single task requires. That habit is exactly what the November update corrects, because a compromised session under the old pattern has a far bigger blast radius than it should.

The fix is incremental scope requests. Instead of asking for everything up front, a server can request more scopes mid-session, exactly when the task in front of it needs them. Alongside that sits a formal Step-Up Authorization Flow: when an operation calls for permissions the current token doesn't cover, the server signals insufficient scope, and the client kicks off a fresh authorization round for just that piece. The agent never grants itself more room to operate. It has to go back to the authorization server and get explicit approval, whether that comes from a user or a policy engine.

This matters because agentic workflows don't stay still. What a task needs at step one is often nothing like what it needs by step seven, and a permission model that only checks in once, at the start, can't track that drift. Incremental scoping and step-up authorization keep least privilege enforced across the whole session, not just at login.

Beyond runtime permissions, the June 2025 spec also shuts down token passthrough outright. An MCP client's token can't simply get forwarded to some upstream API. Do that, and the setup becomes a confused deputy, where a downstream service ends up trusting a token that was never meant for it in the first place.

Diagram: How Step-Up Authorization Keeps Least Privilege Across a Session. Visualizes: Illustrate the incremental scope and step-up authorization flow introduced in the November 2025 MCP spec.

Why static API keys used in most MCP servers today are a structural liability

That Astrix number, 53% of servers running on static keys or personal access tokens, isn't just a snapshot. It's a description of a design flaw baked into most MCP deployments today, and it's the single biggest reason the OAuth mandate exists at all. Anyone still defending static keys as good enough for internal tools is defending the wrong thing, and the defense doesn't hold up past the first incident.

Static keys behave nothing like OAuth tokens. They don't expire on their own, so a leaked key stays live until a human notices and rotates it by hand. They don't carry scope, so the key usually grants whatever the underlying account is allowed to do, full stop. They're not tied to any particular agent or session, so whoever holds the string can use it, and in practice they almost never get rotated once they're sitting in a config file somewhere everyone's forgotten about.

Zoom out and the exposure gets worse. GitGuardian's State of Secrets Sprawl 2026 report found 28.65 million hardcoded secrets added to public GitHub repositories in 2025 alone, a 34% jump year over year and the largest single-year increase on record.

MCP adds its own twist: aggregation. A single MCP server often holds credentials for several downstream services at once, so a compromised server isn't one leaked key. It's simultaneous access across everything that server touches. CVE-2025-49596, rated 9.4 on CVSS, is a clean example. Attackers ran arbitrary commands through unauthenticated MCP Inspector instances, and because the server had no authentication of its own, it became the front door to everything sitting behind it.

Supply chain attacks compound the problem further. The first known malicious MCP package surfaced in September 2025 and quietly pulled email data out for two weeks before anyone caught it. The Smithery supply chain attack that followed in October 2025 hit thousands of hosted applications and the API tokens tied to them.

The OAuth model the spec now requires fixes every one of these weaknesses directly: tokens that expire, tokens scoped to a specific task, tokens bound to a specific audience. Static keys have none of those properties, which is exactly why they don't scale safely. No amount of careful key management changes that math.

The non-human identity problem that OAuth alone does not solve

OAuth was built for a specific job: letting an application act on behalf of a human, with a human somewhere in the loop. Agents break that assumption outright. They're autonomous, they persist across sessions, and they operate at machine speed with none of the friction that naturally slows a human down.

Non-human identities already outnumber human ones by roughly 17 to 1 inside the average enterprise, and that population grew 44% year over year between 2024 and 2025. AI agents are the fastest-growing slice of that group, and they don't behave like the non-human identities that came before them. Service accounts and workload identities are static: fixed roles, predictable actions. Agents reason about what access they need, request new permissions on their own, and produce behavior nobody explicitly programmed.

Handing an agent a human's credentials to work around this creates a governance failure waiting to surface. Human credentials come with human-scale permissions, but an agent using them acts nonstop, with no fatigue and no hesitation to slow it down before it does something wrong. Logging "the model responded X" without recording which tool it called, which scope it used, and which system it touched downstream produces an audit trail that's technically present and practically worthless. Most non-human identities also can't complete MFA, have no behavioral baseline to measure anomalies against, and never go through the lifecycle reviews that flag a human account for a second look.

Veza's 2026 State of Identity and Access report found that 0.01% of non-human identities control 80% of cloud resources. That's concentration risk on a scale that turns every unscoped agent credential into a genuinely high-value target.

Ephemeral, scoped credentials as the operational model for agent access

Zero standing access is the operating principle here: an agent asks for credentials tied to a specific task, uses them, and those credentials expire on their own once the session ends, with no leftover access sitting around waiting to be misused. Anything less than this is just a slower version of the static-key problem, dressed up to look modern. That's not a nuance worth softening; it's the actual dividing line between deployments that hold up and ones that don't.

In practice, that means per-session tokens scoped tightly to the tools and resources a given task actually touches. OAuth 2.1 flows handle the issuing side, and the authorization server checks scope boundaries before a token ever goes out. When the session ends, teardown happens automatically, no residual access left hanging around.

The incremental scope mechanism from the November 2025 spec is what makes this work in real time. Agents don't stockpile permissions upfront; they ask for more only when a task calls for it, and every ask routes back through the authorization server for approval.

PKCE covers one part of this picture, not all of it. It protects the code exchange, but it doesn't authenticate the client making the request. Workload identity closes that gap, binding credentials to the actual runtime environment (a container, a node, a specific deployment) rather than to a string anyone could copy and reuse.

The OWASP MCP Top 10 puts Token Mismanagement and Secret Exposure at the top of its list under MCP01:2025: hardcoded credentials, tokens that never expire, secrets sitting in model memory or protocol logs where they shouldn't be. Platforms like Runlayer, an MCP gateway and AI control plane, address this by enforcing policy and audit at the level of individual tool calls across agent sessions. Identity providers are catching up. Auth0's "Auth for MCP" went generally available in May 2026, and Okta shipped an MCP server that enforces least-privilege access at the level of each individual tool call. The tooling to run this model at enterprise scale exists now, so there's no good excuse left for skipping it.

Any platform still leaning on shared API keys or long-lived static credentials for agent authentication simply can't offer this. The credential setup is either ephemeral and scoped from the ground up, or it isn't. There's no halfway version of this that holds up under pressure.

What tool poisoning and prompt injection reveal about the limits of perimeter-only credential defense

Tool poisoning hides malicious instructions inside an MCP tool's description, text the model reads but the user never sees. Tool descriptions typically get reviewed once, when a connection is first set up, but the responses those tools return flow straight into the model's context with no equivalent check happening at runtime. That unwatched channel is the opening: the agent ends up acting on instructions nobody actually approved. In controlled testing, MCP tool poisoning hit a high success rate when agents had auto-approval turned on. Two CVEs, MCPoison (CVE-2025-54136) and CurXecute (CVE-2025-54135), showed this weakness playing out in two different ways.

Prompt injection across multi-agent workflows follows the same logic from a different angle. One agent's output becomes another agent's input, and malicious content can ride along through a chain of MCP processes, hijacking control flow or triggering data exfiltration several steps downstream. Scoping a token correctly doesn't stop any of this. A token that's perfectly scoped offers no defense against an agent that's been talked into using its legitimate access for something it was never supposed to do.

That's the gap these attacks live in, and it's worth stating plainly: credential hygiene controls what an agent is allowed to do, and it says nothing about what an agent is actually instructed to do once it's running. Catching that requires watching tool calls and intent as they happen, alongside the authorization layer rather than only after it, looking for the moment an agent's actions start drifting from what it was tasked with. Platforms that only check credentials at the door, and never look at what happens once a session is underway, have no way to catch manipulation that plays out entirely inside a session they already approved.

What an audit trail actually needs to capture to be useful

The most common failure here is logging the model's response and stopping there, with no record of the tool calls behind it, the scopes those calls used, or the authorization decisions made downstream. An entry that says an agent "answered a question" exists in the log, technically, but it tells an investigator nothing about what actually happened.

A trail worth having ties every action back to a specific credential, a specific scope, and a specific downstream system touched, so that when something goes wrong, someone can trace exactly which token did what, where, and under whose authorization. A log falls short of that standard the moment it can't answer those three questions, and most logs today can't.

Sources

  1. stytch.com
  2. descope.com
  3. speakeasy.com
  4. den.dev
  5. mcpjam.com
  6. aembit.io

More in Agentic AI Foundations