---
title: "MCP Authentication"
description:
  "How to authenticate MCP servers: method guides with working agent code, what
  each identity provider supports, and fixes for the errors clients report."
canonicalUrl: "https://zuplo.com/learn/mcp/authentication"
sourceUrl: "https://zuplo.com/learn/mcp/authentication"
pageType: "other"
generatedAt: "2026-07-30"
inputsHash: "898100f0acae1fa5"
---

# MCP Authentication

> Every remote MCP server has to decide how callers prove who they are, and the
> specification leaves most of that decision open. This page indexes every
> authentication method with working agent code, compares them, checks
> identity-provider support for the spec's OAuth flow, and links the error
> reference.

## Where to start

The spec makes authorization OPTIONAL, and says HTTP transports SHOULD rather
than MUST use its OAuth flow. So the choice is what your callers can present,
not what the spec requires. A static key works with every agent SDK. Platform
identity avoids a stored secret between workloads you own. The spec's OAuth flow
is what the ChatGPT and Claude connector directories require.

## Authentication methods

Learn how to implement each authentication method, with working code for your
agent.

- **Anthropic-hosted agents** —
  [How an Anthropic-managed agent authenticates to your MCP server](/learn/mcp/authentication/anthropic-managed-agents)
  — Reaching your MCP server from an agent that runs on Anthropic's
  infrastructure
- **API key** —
  [API Key Authentication for MCP Servers](/learn/mcp/authentication/api-key) —
  Service-to-service calls where you control both the agent and the MCP server
- **AWS IAM (SigV4)** —
  [Authenticate an MCP Server with AWS IAM (SigV4)](/learn/mcp/authentication/aws-iam-sigv4)
  — Agents you write that run in AWS, calling a server behind Lambda, API
  Gateway, or AgentCore
- **Client credentials (M2M)** —
  [Machine-to-Machine (M2M) MCP Authentication with the Client Credentials Grant](/learn/mcp/authentication/client-credentials)
  — Cron jobs, CI steps and background workers, where no user is present to
  consent
- **Google Cloud IAM** —
  [Authenticate an MCP Server with Google Cloud IAM](/learn/mcp/authentication/google-iam)
  — Agents that hold Google credentials, calling a server that can verify a
  Google token
- **Microsoft Entra ID** —
  [Authenticate an MCP Server with Microsoft Entra ID (Azure AD) Managed Identity](/learn/mcp/authentication/azure-managed-identity)
  — Agents and MCP servers that both run in Azure, in one Entra tenant
- **mTLS** —
  [mTLS (Mutual TLS) Authentication for MCP Servers](/learn/mcp/authentication/mtls)
  — Workload-to-workload calls where both ends are yours and a CA already issues
  certificates
- **OAuth 2.1** —
  [OAuth 2.1 Authentication for MCP Servers](/learn/mcp/authentication/oauth-2-1)
  — Servers that must be reachable by MCP clients you do not control, or listed
  in a connector directory

## How the methods differ

Compare capabilities of different authentication options for your MCP servers.

| Method                   | Platform              | MCP spec                                                                                                                      | Works with                                                                                                        | Effort                                                             |
| ------------------------ | --------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
| Anthropic-hosted agents  | Claude Managed Agents | Mixed — claude.ai and Claude Code run the spec's OAuth flow; a vault token or a static header sits outside it, not against it | Four surfaces, four credential fields; only Claude Code, which runs locally, sends a header name of your choosing | An afternoon per surface                                           |
| API key                  | Any platform          | Outside the spec's OAuth flow, which the spec makes optional                                                                  | Supported by every agent SDK; hosted connectors are more limited                                                  | An afternoon                                                       |
| AWS IAM (SigV4)          | AWS                   | Platform request signing rather than MCP authorization; the spec does not cover it                                            | Your own agents. No MCP client signs SigV4; AWS ships a local proxy that does                                     | An afternoon with AWS's transport, a day with the IAM policies     |
| Client credentials (M2M) | Any platform          | An official MCP extension, still Draft — shipped in the TypeScript and Python SDKs                                            | Your own agents — the extension support matrix lists no client that implements it                                 | An afternoon, if your IdP already issues client-credentials tokens |
| Google Cloud IAM         | Google Cloud          | Platform identity rather than MCP authorization; the spec does not cover it                                                   | Your own workloads only; no MCP client can mint these tokens                                                      | A day, mostly IAM bindings                                         |
| Microsoft Entra ID       | Azure                 | Out of scope of the spec's OAuth flow, which the spec makes optional                                                          | Your own workloads, plus Microsoft Foundry Agent Service; no chat or desktop client can mint one                  | A day, mostly the app registration and role assignments            |
| mTLS                     | Any platform          | Transport-layer authentication, outside the spec's OAuth profile — which the spec makes OPTIONAL                              | Your own agents only; no chat or desktop client config exposes a certificate field                                | An afternoon in code, longer if the PKI does not exist yet         |
| OAuth 2.1                | Any platform          | The spec's own flow — though the spec still makes authorization OPTIONAL                                                      | Claude, ChatGPT, Cursor and VS Code run it themselves; among agent SDKs, only those shipping an OAuth provider    | Days — most of it is the authorization server, not MCP             |

## What your identity provider supports

The spec's OAuth flow needs dynamic client registration (RFC 7591) and resource
indicators (RFC 8707). Support is patchy, so check yours before you commit to
it.

| Provider                                                                                                             | Registration (RFC 7591) | Resource indicators (RFC 8707) | Notes                                                                                                                                                             |
| -------------------------------------------------------------------------------------------------------------------- | ----------------------- | ------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [Microsoft Entra ID](https://learn.microsoft.com/en-us/entra/identity-platform/v2-protocols)                         | No                      | No                             | No dynamic client registration, and no RFC 8414 metadata endpoint. Ask for an audience with `scope={resource}/.default` rather than the `resource` parameter.     |
| [Amazon Cognito](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-app-idp-settings.html) | No                      | No                             | Cognito's own docs state it does not support dynamic client registration. Pre-register the client.                                                                |
| [Keycloak](https://www.keycloak.org/securing-apps/mcp-authz-server)                                                  | Yes                     | No                             | Keycloak documents that it "cannot recognize the `resource` parameter". Use the `scope` parameter plus an audience mapper on a client scope.                      |
| [Auth0](https://auth0.com/docs/get-started/applications/dynamic-client-registration)                                 | Yes                     | Partial                        | Dynamic registration must be enabled per tenant. Audience is set with the `audience` parameter rather than `resource`.                                            |
| [Ory Hydra](https://github.com/ory/hydra)                                                                            | Yes                     | No                             | Dynamic registration is off by default. Its registration response includes empty `client_uri` and `logo_uri` fields, which some clients reject during validation. |
| [Zitadel](https://github.com/zitadel/zitadel/issues/9810)                                                            | No                      | No                             | Dynamic client registration is not implemented; the tracking issue has been open since April 2025.                                                                |
| [authentik](https://github.com/goauthentik/authentik/issues/8751)                                                    | No                      | No                             | Not shipped. An implementation for the enterprise OAuth2 provider is in review.                                                                                   |

Provider support last verified July 24, 2026.

## When a connection fails

Find and fix the errors MCP clients report when authentication fails.

- **"Your MCP server returns a login page or 403 instead of 401"** — Something
  in front of your MCP server is enforcing authentication built for humans in
  browsers, so the client never gets the 401 it needs.
- **"Resource server does not implement OAuth 2.0 Protected Resource
  Metadata."** — Your server answers 401 correctly, but the response carries no
  pointer to protected resource metadata, so the OAuth flow never starts.
- **"The request signature we calculated does not match the signature you
  provided"** — AWS recomputed the SigV4 signature and got a different value,
  and answered 403 before your MCP server ran.
- **"MCP headers config ignored when server has OAuth discovery"** — The client
  found OAuth discovery metadata on your server first and switched to the OAuth
  flow instead of sending the header you configured.
- **"Dynamic Client Registration not supported"** — The MCP client found no way
  to obtain a client ID from your authorization server's metadata.
- **"Failed to fetch authorization server metadata from all attempted URLs"** —
  None of the well-known URLs the client is required to try returned a metadata
  document.
- **"mcp_authentication_failed_error"** — A managed agent's connection failed on
  authentication: the server rejected the vault credential, required auth with
  none configured, or an `mcp_oauth` mismatch.
- **"Couldn't reach the MCP server"** — One toast covers four different
  failures, since Claude Code/curl reach your server from your machine while a
  claude.ai connector reaches it from Anthropic's infrastructure.
- **"Authorization with the MCP server failed"** — A token was issued and the
  client says it's connected, but the credential never reaches your server
  intact, or it carries an audience your server rejects.
- **"resource indicator is missing, or unknown"** — The authorization server
  refused to bind a token to your MCP server because the `resource` value is
  unrecognized or mismatched.
- **"Token audience validation failed"** — The token is real, but its `aud`
  claim names something other than this MCP server, so the server is required to
  reject it.

See the full [error reference](/learn/mcp/errors) to search by the exact string
your client reported.

## Next steps

- Read a specific authentication method guide (linked above) for working agent
  code
- Check identity provider support before committing to the spec's OAuth flow
- Search the [MCP error reference](/learn/mcp/errors) for a client-reported
  error string
- Start a free account: https://portal.zuplo.com/signup
- Read the docs: https://zuplo.com/docs/mcp-gateway/code-config/overview
