When a remote MCP server rejects an agent, the visible symptom is usually a vague "unauthorised" or a loop of browser sign-ins, while the real fault sits in one of six hops between the client, the MCP server and the authorisation server. The MCP authorisation specification builds on OAuth 2.1, Protected Resource Metadata (RFC 9728), Resource Indicators (RFC 8707) and Bearer token rules (RFC 6750), and each layer has its own error. This guide is a symptom-led diagnostic reference for engineers who build or operate MCP servers, clients and gateways. It maps each symptom to its likely causes, tells you where to look, and gives fixes that keep audience binding and least privilege intact. The specification itself is explained in the MCP Authorisation Specification Guide, which this page does not repeat. Requirements were checked against the 2025-11-25 revision of the specification on 11 November 2026.
Key takeaways
- 401 and 403 mean different things. The specification requires 401 for missing, invalid or expired tokens and 403 for insufficient scope or permission; 400 is for malformed authorisation requests. A server that blurs them breaks client recovery.
- Discovery failures look like authentication failures. If the client cannot find Protected Resource Metadata, or the metadata's
resourcevalue does not match the URL it called, it must stop, and users see a generic sign-in error. - Audience mismatch is the most important error to keep. Servers must reject tokens not issued for them. Never "fix" an audience error by accepting any token from the issuer.
- Scope loops need retry limits. A 403
insufficient_scopeshould trigger at most a few step-up attempts; endless re-consent prompts mean the server's challenge or the authorisation server's scope policy is wrong. - Local servers are different. The specification says STDIO transports should not follow this flow and take credentials from the environment, so a local server "auth error" is usually a missing or wrong environment credential.
Where MCP authorisation can fail
For HTTP transports the flow has six hops. Every error you will see belongs to one of them.
| Hop | What should happen | Typical failure symptom |
|---|---|---|
| 1. Challenge | MCP server returns 401 with WWW-Authenticate: Bearer resource_metadata="...", ideally with scope | Client reports "server requires auth" but never opens a browser; or the 401 is swallowed by a proxy |
| 2. Resource metadata | Client fetches Protected Resource Metadata and validates resource; reads authorization_servers | 404 on the well-known path; "resource mismatch"; empty authorization_servers |
| 3. Authorisation server metadata | Client tries OAuth and OpenID discovery endpoints in a fixed order; checks PKCE support | Discovery 404s; client refuses because code_challenge_methods_supported is missing |
| 4. Client registration | Pre-registration, Client ID Metadata Document, or Dynamic Client Registration | invalid_client, invalid_redirect_uri, registration endpoint absent |
| 5. Authorisation and token | Authorisation code with PKCE S256 and the resource parameter | invalid_grant, invalid_target, state mismatch, consent loop |
| 6. Token use | Bearer token in the Authorization header on every request; server validates audience | 401 invalid_token after a successful sign-in; 403 insufficient_scope on some tools |
Work forwards from hop 1. The commonest wasted effort is reconfiguring the authorisation server (hop 5) when the MCP server never emitted a usable challenge (hop 1) or published metadata at the wrong path (hop 2).
Error and status reference
Bearer error codes come from RFC 6750 Section 3.1; OAuth endpoint errors from OAuth 2.1 and RFC 8707; MCP-specific status rules from the specification's Error Handling section.
| Response | Defined meaning | Most likely MCP causes | Where to look |
|---|---|---|---|
401 with no error | Request had no authentication information (RFC 6750 says no error code should be included) | First call before sign-in (expected); client not attaching the header; proxy stripping Authorization | Client request log; reverse proxy header policy |
401 error="invalid_token" | Token expired, revoked, malformed or otherwise invalid | Expired access token not refreshed; wrong audience; signing key not in the JWKS the server trusts; clock skew | Decode token claims; server validation log |
403 error="insufficient_scope" | Valid token lacks privileges; server may name the needed scope | Tool needs a scope not yet granted; user lacks the role the scope maps to | WWW-Authenticate scope list; authorisation server policy |
400 invalid_request | Malformed request, missing or duplicated parameter | Token sent in query string and header; missing PKCE verifier | Client request construction |
invalid_target (authorisation or token endpoint) | RFC 8707: requested resource invalid, missing, unknown or malformed, or an invalid resource and scope combination | Client resource differs from canonical server URI (trailing slash, port, path) | Authorisation server log; client config |
invalid_client | Client authentication or identification failed | CIMD document client_id does not equal its own URL; stale DCR registration | Fetch the metadata document; registration records |
invalid_grant | Code or refresh token invalid, expired or already used | PKCE verifier mismatch; rotated refresh token reused; code redeemed twice | Authorisation server token log |
Related OAuth endpoint errors are diagnosed in depth in the OAuth invalid_grant Error Troubleshooting Guide and the OAuth invalid_client and unauthorized_client Troubleshooting Guide.
Symptom 1: the client never starts sign-in
Likely causes, most to least common:
- No usable challenge: the server returns 401 without
resource_metadataand does not serve the well-known document either. The specification requires one of the two. Check with a plain unauthenticated request and inspect theWWW-Authenticateheader. - Wrong status: the server returns 403 or 500 for a missing token. Clients key the discovery flow on 401, so they never begin.
- Infrastructure rewriting: an API gateway, WAF or CDN replaces the 401 body and drops
WWW-Authenticate, or the CORS policy does not expose the header to a browser-based client. - Transport confusion: the server is local (STDIO) and expects a credential in an environment variable; there is no OAuth flow to start.
Fix: return 401 with WWW-Authenticate: Bearer resource_metadata="https://host/.well-known/oauth-protected-resource/mcp" and a scope parameter, serve the same document at the well-known path, and allow the header through every proxy layer.
Symptom 2: metadata or discovery errors
Protected Resource Metadata
RFC 9728 inserts /.well-known/oauth-protected-resource between the host and any path. For an MCP endpoint at https://example.com/public/mcp the path form is https://example.com/.well-known/oauth-protected-resource/public/mcp; clients fall back to the root form /.well-known/oauth-protected-resource. Two rules cause most failures:
- Resource must match: the document's
resourcevalue must exactly match the identifier used to build the URL, and when the URL came from a challenge it must match the URL the client called. A document that sayshttps://example.comfor a server at/public/mcp, or useshttp, is rejected. - At least one authorisation server: the MCP specification requires
authorization_serverswith at least one entry.
Authorisation server metadata
For an issuer with a path such as https://auth.example.com/tenant1, clients must try, in order, /.well-known/oauth-authorization-server/tenant1, /.well-known/openid-configuration/tenant1, then /tenant1/.well-known/openid-configuration. Many identity providers serve only the last form, so a client that stops at the first 404 is non-compliant; a provider that serves none of them cannot be used.
PKCE gate: clients must refuse to continue if code_challenge_methods_supported is absent from the metadata, and authorisation servers using OpenID discovery must include it. If an otherwise working identity provider is rejected, check this field first.
Symptom 3: registration and redirect errors
| Registration route | Common error | Cause and fix |
|---|---|---|
| Client ID Metadata Document | invalid_client or invalid_request | The document's client_id must equal its HTTPS URL exactly, and it must include client_id, client_name and redirect_uris. Check the authorisation server advertises client_id_metadata_document_supported. |
| Dynamic Client Registration | Registration endpoint 404 or 403 | No registration_endpoint in metadata, or the authorisation server restricts open registration. DCR is optional in the current revision. |
| Pre-registration | unauthorized_client, redirect mismatch | Client ID created for a different grant type, or the local callback port differs from the registered redirect URI. |
| Any | Redirect URI rejected | Redirect URIs must be localhost or HTTPS and match exactly a registered value. |
Do not relax exact redirect matching to make a client work. The specification notes that a localhost redirect cannot prove which application is listening, which is why servers should warn on localhost-only clients and show the redirect host to the user.
Symptom 4: sign-in succeeds, then 401 invalid_token
This is the classic audience or validation failure. Decode the access token (if it is a JWT) in a local tool, never an online decoder, and compare:
aud: must identify this MCP server. The client must sendresourcewith the canonical server URI in both the authorisation and token requests. The specification prefers no trailing slash, lowercase scheme and host, and the most specific URI (for examplehttps://mcp.example.com/mcp). A token minted forhttps://mcp.example.commay fail at a server that expects the/mcpform, or the reverse.iss: must be an issuer the server trusts, with keys in its cached JWKS. After the authorisation server rotates signing keys, servers with stale caches reject every new token. See the JSON Web Key Sets (JWKS) and Signing Key Rotation Guide.exp,nbf,iat: check clock skew between server and issuer. Long agent tasks often outlive short access tokens; the client must refresh. For public clients the authorisation server must rotate refresh tokens, so a client that keeps using an old refresh token getsinvalid_grant.- Header placement: the token must be in
Authorization: Beareron every HTTP request in the session and never in the query string.
Generic token claim failures are covered in the JWT Validation Errors Troubleshooting Guide.
Symptom 5: 403 insufficient_scope and consent loops
The server should answer a runtime shortfall with 403 and WWW-Authenticate: Bearer error="insufficient_scope", scope="...", resource_metadata="...". The client should treat the challenged scopes as authoritative, re-authorise, and retry only a few times. Loops have three usual causes:
- Server drops granted scopes: the challenge lists only the new scope, so the new token loses the old one and the next tool call fails. The specification recommends including existing relevant scopes plus the new ones.
- Policy denies silently: the authorisation server issues a token without the requested scope because the user lacks entitlement. The client asks again, gets the same token, and loops. Make the authorisation server return an error or the client compare granted with requested scopes.
- Machine clients: a
client_credentialsclient cannot get user consent; the specification allows it to abort. Treat the 403 as a configuration task, not a retry.
Gateways, proxies and token passthrough
An MCP server that calls upstream APIs must act as a separate OAuth client to them. The specification states the server must not pass through the token it received. Errors that appear only on upstream calls (an upstream 401 relayed to the agent) usually mean the server is forwarding the client's token, which the upstream rightly rejects because it was issued for the MCP server. The fix is a token exchange or a separate upstream credential, never widening the upstream's audience check. See the Confused Deputy in AI Agents Guide. Gateways add their own hop: check that the gateway preserves WWW-Authenticate, does not cache 401 responses, and that the canonical URI clients see is the one the authorisation server binds tokens to. The LiteLLM MCP auth bypass shows how weak token checks at a gateway expose every credential behind it.
Testing fixes and rolling back
- Reproduce with a scripted client: send an unauthenticated request, record the challenge, fetch both metadata documents and record each response. This isolates hops 1 to 3 without a browser.
- Use a test tenant: change scope policy, registration settings or audience configuration in a non-production authorisation server tenant first.
- Change one hop at a time: and re-run the scripted client after each change.
- Canary the server change: roll new challenge headers or audience rules to one instance behind the gateway and watch 401 and 403 rates.
- Roll back on rate spikes: keep the previous metadata documents and validation configuration versioned so they can be restored quickly; never roll back by disabling validation.
Detection and measurement
Authorisation errors are also an attack signal: replayed tokens, tokens for other resources and scope probing all surface as 401 and 403.
- Log at the MCP server: status, Bearer error code, token
iss,aud, client ID, subject, requested tool and the scopes required versus present. Never log the token itself. - Log at the authorisation server: registration events,
invalid_target,invalid_granton refresh, and new CIMD client domains. - Watch for: tokens with a foreign audience (possible reuse of a stolen token, ATT&CK T1550.001 Application Access Token), bursts of 403 across many tools from one client, and new client IDs registering redirect URIs on unfamiliar hosts.
| Metric | Healthy signal |
|---|---|
| 401 rate after successful sign-in (per client) | Near zero; spikes follow key rotation or audience changes |
| Step-up attempts per operation | One; more than three indicates a scope loop |
| Tokens rejected for wrong audience | Low and investigated individually |
| Servers publishing valid Protected Resource Metadata | 100% of remote MCP servers in inventory |
| Servers forwarding inbound tokens upstream | Zero |
Common failure patterns
- Accepting any token from the issuer: removing the audience check to end 401s turns the server into a target for tokens stolen from other services.
- Trailing slash drift: the client, metadata and authorisation server disagree on
https://host/mcpversushttps://host/mcp/. - Returning 403 for missing tokens: clients never start discovery.
- Granting every scope to stop prompts:
scopes_supportedshould be the minimal set, with more requested by challenge. - Token passthrough: upstream failures are "fixed" by loosening the upstream, creating a confused deputy.
- Treating a local server as remote: engineers build an OAuth flow for a STDIO server that should simply read a scoped credential from its environment.
Framework mapping
| Framework | Reference | Relevance |
|---|---|---|
| NIST CSF 2.0 | PR.AA-03, PR.AA-05 | Authenticating clients and agents; enforcing scoped permissions |
| NIST SP 800-53 Rev. 5 | AC-3, AC-6, IA-5, AU-2 | Access enforcement, least privilege, token management, logging |
| OWASP ASVS 5.0 | V9.2.1 | Token validity time checks at the resource server |
| ISO/IEC 27001:2022 Annex A | 5.15 Access control, 8.5 Secure authentication | Policy and mechanism for agent access |
| MITRE ATT&CK v20 | T1528 Steal Application Access Token, T1550.001 Application Access Token | Threats the audience and scope checks defend against |
Practitioner checklist
- Return 401 with
resource_metadataandscopefor missing or invalid tokens, 403 withinsufficient_scopefor missing privileges. - Serve Protected Resource Metadata at the path-inserted well-known URI with an exact
resourcematch. - Confirm the authorisation server publishes
code_challenge_methods_supportedand is discoverable by one of the three URIs. - Fix one canonical URI for each server and use it in client config, metadata and audience rules.
- Validate
aud,iss, signature and time on every request; keep JWKS caches refreshable. - Include existing scopes in step-up challenges and cap client retries.
- Never pass the client's token upstream.
- Log error codes and claims, not tokens, and alert on foreign-audience tokens.
Standards and references
- Model Context Protocol: Authorization (2025-11-25)
- IETF: RFC 9728 OAuth 2.0 Protected Resource Metadata
- IETF: RFC 6750 OAuth 2.0 Bearer Token Usage
- IETF: RFC 8707 Resource Indicators for OAuth 2.0
- IETF: The OAuth 2.1 Authorization Framework (Internet-Draft)
- MITRE ATT&CK: T1550.001 Application Access Token
Related NHI Mgmt Group resources: MCP Authorisation Specification Guide, MCP Security Guide, MCP Gateway and MCP Server Governance Guide, Local MCP Server Security Guide, MCP Incident Response Playbook.