enterprise MCP authentication
Enterprise MCP authentication is how an organization’s Model Context Protocol
(MCP) servers establish who is on the other end of a connection: which client
software is asking, and which principal, a person or an autonomous agent, it
acts for. MCP authenticates over OAuth 2.1. The principal is confirmed by the
corporate identity provider, and
the client software is confirmed by the way it obtains its client_id, which
has moved from hand registration to Dynamic Client Registration to Client ID
Metadata Documents.
Enterprise MCP authentication is how an organization’s Model Context Protocol (MCP) servers establish who is on the other end of a connection: which client software is asking, and which principal, a person or an autonomous agent, it acts for. MCP authenticates over OAuth 2.1. The principal is confirmed by whichever identity provider the authorization server trusts, which in an enterprise is the corporate directory. The client software is confirmed by the way it obtains its client_id. That mechanism has changed twice since MCP adopted OAuth: from clients registered by hand, to Dynamic Client Registration (DCR), to Client ID Metadata Documents (CIMD).
In its April 2026 research note, the Cloud Security Alliancenoted that, 71% of 235 large-enterprise CISOs and CIOs said AI had access to core business systems, while only 16% said that access was being governed effectively. MCP is a growing share of how that access arrives, as a client on an employee laptop pointed at a server, and until recently the server had no reliable way to know which client it was.
This page walks through the evolution of MCP authentication, and covers what an enterprise deployment adds on top and where authentication hands off to authorization.
Authentication and authorization are different questions
Authentication establishes who is on the connection. Authorization decides what they may do. On an MCP connection, authentication answers two questions: which client software is asking, and which principal is it acting for. Authorization answers a third, asked on every tool call: may this identity run this tool with these arguments right now.
Two identities on every MCP connection
Every MCP session carries two identities: the principal it acts for, and the client software making the request. An enterprise has to be able to name both.
The principal is the easier one, because the machinery already exists. When the principal is a person, the authorization server that issues MCP tokens sends the login to Okta, Microsoft Entra ID, or any SAML or OIDC provider, so group membership and conditional access apply and disabling the account stops new sessions. When it is an autonomous agent, it acts under a non-human identity of its own that the same directory governs, in place of a borrowed user account. What qualifies as an agent principal is covered in agent identity. Making that work across many servers without a consent screen for each is the subject of MCP SSO.
The client software is the harder one, and the difficulty is specific to MCP. A traditional OAuth client, such as a mobile app talking to its own backend, is registered once with one authorization server by the team that built both. An MCP client such as Claude Code, Cursor, or VS Code ships before the servers it will be pointed at exist, and one install may reach dozens of authorization servers run by different organizations. Each of those servers has to give the client a client_id before an OAuth flow can start. How it does that decides whether the organization can later say which client software connected, put a name on the consent screen that someone vouched for, and write a rule about which clients may connect at all. The rest of this page follows that mechanism through its three forms.
OAuth with pre-registered clients
Plain OAuth is where MCP started, and it is the model every other OAuth deployment uses. Before a client can begin, an administrator registers it at the authorization server: a name, a set of redirect URIs, and a client_id the server mints and hands back out of band. When the client later arrives, the server already knows it.
- Claude Codeclient_id 4c1f9etyped in by an admin
- Cursorno client_idnever registered, cannot start
The flow itself is the one all three variants share. The client calls the MCP server with no token and receives a 401 whose protected resource metadata (RFC 9728) names the authorization server. It sends an authorization request with PKCE and a resource parameter naming the server (RFC 8707). The user signs in, in an enterprise through the identity provider, and approves the consent screen. The authorization server issues a token bound to that server, and the client presents it on every MCP request.
Pre-registration gives the strongest client identity of the three, because a human reviewed the client before it existed at this server. Its ceiling is arithmetic. Every client at every server needs a registration, done by hand, before anyone can connect. Three clients and forty servers is 120 registrations, each owned by whoever runs that server, and a client release with a new redirect URI reopens all of them. For a company running a few in-house servers with a fixed set of clients this is manageable. For an ecosystem where clients and servers are built by different parties and meet for the first time on a laptop, it does not work, which is why MCP needed something else.
OAuth with Dynamic Client Registration
Dynamic Client Registration (RFC 7591) removes the human from registration. The client POSTs a short JSON body, a display name and its redirect URIs, to a registration endpoint on the authorization server and receives a freshly minted client_id in response. MCP adopted OAuth in large part because DCR existed. It let any client obtain a client_id from any server without anyone visiting a developer portal.
- “Claude Code”client_id a91e07self-asserted
- “Claude Code”client_id 7d02c3reinstall
- “Claude Code”client_id f3b91asecond laptop
- “Claude Code”client_id 0c44deunknown origin
After registration the flow is identical to the pre-registered case: PKCE, identity provider login, consent, token, tool call. What changed is who asserted the client’s identity, and three limitations follow from the answer.
Everything in the registration is self-asserted. The server receives a POST with no signature and no proof that a real vendor sent it, and records whatever the body says. A malicious app can register with client_name: "Claude", and when a user reaches the consent screen it reads “Claude wants to access your account”. Pre-registration avoided this because a human looked at the app first.
Every install registers separately. Registration is per instance, so each copy of Claude Code on each laptop does its own POST and receives its own client_id. A company with 500 engineers on three tools ends up with more than 1,500 client records, and the count grows on every reinstall. None of the rows carry verifiable information, so an administrator looking at the table cannot tell live installs from stale ones or from something suspicious.
There is nothing to allowlist. Under open DCR, the set of clients allowed to start a flow at /authorize is anyone who registered, and anyone can register. A server that wanted a rule saying only Claude Code and VS Code may request access has nothing reliable to write it against, because names are typed and identifiers are random per install. This is the first question a security review asks, and DCR has no answer for it.
DCR was the right call when MCP adopted OAuth, and it still works with any client that speaks OAuth at all. Its weaknesses follow directly from its design, and no configuration on the authorization server removes them.
OAuth with Client ID Metadata Documents
A Client ID Metadata Document replaces the registration call with a URL. The client vendor publishes a JSON document describing the client, its name and its permitted redirect URIs, at an HTTPS address on a domain it controls. That URL is the client_id, the same one at every authorization server and on every install.
- Claude Codehttps://vendor.example/oauth/client.jsonsame URL on every install
When the client presents the URL, the authorization server checks it against whatever admission policy it has, fetches the document over HTTPS, confirms the client_id inside matches the URL it came from, checks the redirect URI the client sent against the ones the document lists, and caches the result. No registration happens and no rows accumulate. The rest of the flow is unchanged: the user still signs in through the identity provider, PKCE still binds the code to the client, and the token is still scoped to the server.
Two things change. The name on the consent screen comes from a document on the vendor’s domain, so the domain vouches for it. And the identifier is durable, so an allowlist becomes a list of URLs, an audit search becomes a search on one identifier, and revoking a client holds on the next install because the next install presents the same URL.
MCP adopted CIMD through SEP-991, merged in November 2025, and the 2026-07-28 specification says clients and authorization servers SHOULD support CIMD and MAY support DCR, which it marks deprecated but retains for compatibility. Authorization servers advertise support with client_id_metadata_document_supported in their metadata, and a client that supports every option tries pre-registered credentials first, then CIMD, then DCR. The underlying IETF document is an active Internet-Draft in the OAuth working group, and it will be revised.
Two caveats belong in a design review. CIMD names the client software and attests its redirect URIs; it does not attest which process is running. A local attacker can present a legitimate client’s metadata URL and bind the same loopback port, and SEP-991 says the exposure matches DCR in that scenario. And an authorization server that fetches a client-supplied URL has taken on a server-side request forgery surface a DCR server never had, so the fetch needs URL and IP validation, size and time limits, and rate limiting. The full comparison, including where DCR’s defenders are right, is in CIMD vs DCR for MCP OAuth.
How the three mechanisms compare
| Pre-registered | Dynamic Client Registration | Client ID Metadata Document | |
|---|---|---|---|
| Who asserts the client’s identity | An administrator, by hand | The client, about itself | The vendor, through a document on its domain |
| Identifier across installs and servers | Stable per server, entered by hand | Different on every install and at every server | The same URL everywhere |
| Works with a client the server has never seen | No | Yes | Yes |
| Name on the consent screen | Typed by the administrator | Typed by the client | Published by the vendor |
| Client allowlist | Possible, maintained by hand | Nothing stable to write it against | A list of URLs |
| Status in MCP 2026-07-28 | Supported | Deprecated, retained as a MAY | SHOULD |
What an enterprise adds to MCP authentication
The specification’s flow, run per server, authenticates one client and one principal to one server. Enterprise MCP authentication runs the same flow with four things fixed centrally.
- The principal resolves to the directory. The human login behind every consent screen is federated to the corporate identity provider, so the account is the corporate one, conditional access applies, and deprovisioning stops new sessions. Enterprise-Managed Authorization (EMA) lets the identity provider issue the grant directly for clients and servers that have implemented it, and a gateway federates the login for the rest. MCP SSO owns that comparison. An agent principal is issued and revoked in the same directory rather than running on a user’s credentials.
- The client resolves to a policy. With CIMD-capable clients, the authorization server carries an admission policy: approved client URLs are admitted, unknown ones are refused or held for review, and revoking a client means removing its URL. Because a client release can present a new metadata URL, the policy runs in an observe-only mode first and is enforced once the list matches the clients people already use. DCR stays on for clients that have not shipped CIMD and is switched off when the server’s own logs show no registrations arriving.
- One authorization server in front of a mixed estate. Vendor servers, internal servers, and servers that only ever had an API key sit behind the same MCP-facing authorization server, so every client completes one flow and the policy above applies to all of them. This is the role an MCP gateway plays, and it is why the identity provider alone cannot fill it. An MCP client discovers its authorization server from the MCP server’s resource metadata, expects it to accept a URL-shaped or unregistered client, and speaks no SAML. Okta and Entra ID stay the source of truth for who works here, and something MCP-shaped presents the OAuth surface on their behalf.
- Upstream credentials leave the laptop. The API keys and OAuth tokens each backend needs are held by the component on the path, encrypted at rest and released per session. Employees hold a session bound to their directory identity instead of a personal access token per server, which is the credential nothing in the directory can currently see or revoke. The shape of that fix is the subject of task-scoped credentials.
Authorization sits on top of all four. Once a session exists for a verified client acting for a directory user, a policy evaluated on every tool call decides what that session may do, and the identity the four controls above produce is what that policy decides about.
What are the trade-offs?
A gateway acting as the authorization server is a chokepoint by design. Every MCP session depends on its availability, every tool call takes one more hop, and the upstream credentials it holds are concentrated in one place. Concentration is what makes the credentials governable and is also what makes the component worth attacking, so it needs the operational attention of an identity system.
Where EMA and a gateway coexist, policy lives in two places. Grants for EMA-capable servers are decided in the identity provider, and grants for everything else are decided at the gateway. Both are directory-driven, and an access review has to read both to answer who can reach what.
Revocation runs on different clocks. Disabling an account stops new sessions on the same event that stops sign-in. Existing gateway tokens end on their configured lifetime. Upstream OAuth tokens that a gateway holds on a user’s behalf can remain valid at the upstream service until they are revoked there, so an offboarding runbook that stops at the directory has not finished.
Client allowlists have an ergonomics cost. CIMD is a draft and will change, a new client version may ship a new metadata URL, and a policy switched to enforce without an observation period blocks people who authenticated yesterday. Allowlisting also names the software without attesting the process, so it raises the cost of impersonation on a laptop without removing it.
Do I need enterprise MCP authentication?
You need it when at least two of the following are true: more than one AI client reaches more than a handful of MCP servers; some of those servers authenticate with API keys or personal access tokens; a security or identity team has to answer which clients and which people can reach a given system; or offboarding has to end MCP access on the same day it ends everything else.
You do not need it yet if a small team runs a few in-house servers with per-server OAuth against its identity provider, or if every client and server in use supports EMA. Run the specification’s flow, and write down the server count at which you will revisit.
If the answer is yes, the work orders itself. Get personal access tokens off laptops first, by putting upstream credentials behind a component that holds them and issues sessions instead. Federate those sessions to the directory second, so offboarding works. Add a client admission policy third, in observe mode and then enforced, once CIMD-capable clients are the majority of what connects. Put an authorization decision on every call after that, because it depends on the first three having produced an identity worth deciding about.
A note on Speakeasy
The Speakeasy AI Control Plane runs an OAuth 2.1 authorization server for each MCP server behind its MCP gateway, hosted or proxied, with PKCE, so a client completes one flow against the control plane rather than one per backend. That authorization server accepts all three client identities described above. Pre-registered clients are unchanged. Clients that still speak DCR register the way they always have, and there is no deprecation date for it. Clients that present a Client ID Metadata Document, including Claude Code and VS Code, have the document fetched, checked to confirm it names itself, and the redirect URI validated before the flow continues, loopback redirects included (release 1.1.0).
Each issuer carries an admission policy for CIMD clients. Open, the default, admits any URL that resolves to a valid document. Presets admits a URL only if it matches a catalog Speakeasy maintains of client documents published by the vendors seen most in production, including Claude Code, Claude, VS Code, Zed, ChatGPT, and Codex CLI, or a custom URL added to the issuer for an internal client. A miss under presets is a hard invalid_client with no fallback to DCR (1.5.0, 1.9.0). Catalog matching is by exact URL rather than origin. Custom URLs can be verified before saving, with the reason for a failure reported. Admission gates the start of a flow and not the continuation of one, so a catalog change does not end sessions already authorized, and every mode change is written to the audit log. Issuers that have not chosen a mode record what presets would have decided without enforcing it, which is the observation period described above. Organization admins manage issuers and their clients once, inherited by every project, from the dashboard, the management API, or the Platform MCP (1.22.0). The same support runs outbound: when an upstream authorization server accepts CIMD, the platform hosts a client metadata document and presents its URL as the client ID with no shared secret (0.78.0). GitHub, Slack, Google, and Atlassian do not accept CIMD today, so most upstream connections still use DCR or a pre-registered client.
On the principal, sessions federate to Okta, Microsoft Entra ID, Auth0, WorkOS, Google Workspace, Ping Identity, or any SAML or OIDC provider, and with Directory Sync connected a deprovisioned user loses MCP access as the directory changes. Upstream credentials for the backends are held by the platform, encrypted at rest and refreshed silently. Connect, view, and manage rights are set per principal on each server, independently of one another.
Four limits apply. Speakeasy does not implement the EMA ID-JAG exchange; for client-server pairs that both support EMA, the identity provider route is available, and Speakeasy governs the servers that have not implemented it, which in most estates is the majority. CIMD support covers public clients, which use token_endpoint_auth_method of none and are what shipping MCP clients use today; confidential client authentication is separate work. The default admission mode is open, so enforcing a client allowlist is a choice an operator makes, and an issuer nobody has configured is not allowlisting anything. And revoking a connection invalidates the token the gateway issued without revoking the upstream OAuth token held for that user, which can remain an active session at the upstream service until it is revoked there.
MoonPay runs this path in production. Client registration started on DCR and moved to CIMD when the specification deprecated DCR, without the security team planning the migration, and the durable identity CIMD gives each client is what lets MoonPay allowlist approved clients and keep unsanctioned servers blocked by default. If you are trying to write down which AI clients and which people may reach your MCP servers and finding that you cannot, we would like to hear how you are approaching it. Talk to us.