[Blog](https://cohesivity.ai/blog)

MCP

Published Jul 8, 2026·Updated Aug 30, 2026

![](https://cohesivity.ai/authors/shouryamaan.webp)![](https://cohesivity.ai/authors/anshu.webp)[Shouryamaan](https://www.linkedin.com/in/shouryamaanjain/) and [Anshu](https://www.linkedin.com/in/aanshuaggrawal120/)

# The Complete Guide to MCP Authentication and Authorization

[Read as Markdown](https://cohesivity.ai/blog/mcp-authentication-and-authorization-guide.md)

Access

Credential

Identity

Policy

Audit

MCP authentication identifies the client and represented user. Authorization decides which tools, tenants, resources, and actions they may access. For remote HTTP servers, the current MCP specification uses OAuth discovery, PKCE, resource indicators, bearer tokens, and audience validation. The backend still has to authorize the final resource.

Local stdio servers use their process environment instead of this HTTP authorization flow. Do not copy a remote OAuth design into stdio merely for protocol symmetry.

## The roles in remote MCP authorization

The [MCP authorization specification](https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization) defines three roles:

- The MCP client acts as an OAuth client.
- The MCP server acts as the protected resource server.
- The authorization server authenticates the resource owner and issues access tokens.

The authorization server may be part of the same service or a separate identity platform. The MCP server is still responsible for validating the token and enforcing access.

## Discovery begins with the protected resource

When a client calls a protected MCP server without valid authorization, the server returns `401` with a `WWW-Authenticate` header pointing to protected-resource metadata. That metadata tells the client which authorization server or servers can issue tokens for this resource.

The client then reads OAuth authorization-server metadata to find authorization and token endpoints. MCP requires protected-resource metadata and authorization-server metadata because a general client may connect to a server it has never seen before.

## Bind the request to the MCP server

The client includes a `resource` parameter in both authorization and token requests. That value identifies the intended MCP server. The MCP server must then confirm that the presented token was issued for it.

This audience binding prevents a token issued for one service from being replayed against another. A valid signature is insufficient when the audience is wrong.

## Protect the authorization code

Public MCP clients cannot safely hold a client secret. The specification requires Proof Key for Code Exchange, known as PKCE, so the client that started the flow proves possession of a verifier when exchanging the authorization code.

Redirect URIs must be registered and matched exactly. Clients should use and verify a state value to bind the callback to the request they started. HTTPS is required except for localhost development redirects.

## Send tokens only in the authorization header

Every protected HTTP request carries:

```http
Authorization: Bearer <access-token>

```

The MCP specification forbids access tokens in query strings. URLs leak into browser history, reverse-proxy logs, analytics, screenshots, and referrer data more easily than headers.

Invalid or expired tokens return `401`. A valid identity with insufficient scope or permission returns `403`.

## Never pass the MCP token downstream

The access token is intended for the MCP server. The server must not forward it to a third-party API. If the tool calls an upstream service, the MCP server acts as a separate OAuth client or retrieves a separate backend credential intended for that service.

Token passthrough creates a confused-deputy problem and breaks audience boundaries. The [MCP API-key guide](https://cohesivity.ai/blog/mcp-security-api-keys) covers where those upstream credentials should live.

## Authorize the user, tenant, resource, and action

Scopes are only one layer. After validating the token, calculate access from current application state:

1. Which user or service identity is represented?
2. Which tenant or organization is active?
3. Is the requested resource owned by that tenant?
4. Is this action allowed for the identity's role?
5. Does the action require a current approval or policy decision?
6. Is the credential still active and within its limits?

The downstream API should repeat the resource-level authorization. A tool named `read_invoice` does not make the API call read-only by declaration.

## Keep high-impact approval separate

OAuth consent grants a class of access. It should not be treated as approval for every future deletion, purchase, or broad mutation. At call time, show the exact resource and effect for consequential actions.

The MCP tools specification recommends clear user visibility and confirmation around tool invocation. The [safe infrastructure guide](https://cohesivity.ai/blog/how-ai-agents-safely-manage-cloud-infrastructure-through-mcp) adds plan and apply boundaries for cloud actions.

## Test the failure cases

| Test                                 | Expected result                               |
| ------------------------------------ | --------------------------------------------- |
| No bearer token                      | 401 with protected-resource metadata location |
| Expired token                        | 401 without backend execution                 |
| Token for another audience           | Rejected before tool dispatch                 |
| Valid token, missing scope           | 403                                           |
| Correct scope, wrong tenant resource | Non-disclosing denial                         |
| MCP token presented to upstream API  | Impossible by construction                    |
| Modified redirect URI                | Authorization rejected                        |
| Replayed destructive request         | One effect or approval required               |

Also inspect logs, error trackers, traces, and analytics for access and refresh tokens. Correct validation does not help if the server records the credential.

## Trace one token to its stopping point

Start at the first unauthenticated request and follow the issued access token until the MCP server validates it. Then follow the separate upstream credential. If the same token crosses both boundaries, stop and fix that before adding tools.

The prompt below produces that trace and the missing tests without invoking the server.

or send it to[Claude Code](https://claude.ai/new?q=Audit+this+remote+MCP+server%27s+authentication+and+authorization+without+making+external+calls.+Trace+one+protected+tools%2Fcall+request+from+401+discovery+through+authorization-server+metadata%2C+client+registration%2C+PKCE%2C+resource+indicators%2C+token+issuance%2C+bearer+validation%2C+audience+checks%2C+scopes%2C+tenant+and+resource+authorization%2C+and+the+upstream+API+request.+Cite+exact+files+and+configuration.+Flag+access+tokens+in+URLs%2C+token+passthrough%2C+missing+audience+validation%2C+broad+upstream+credentials%2C+absent+downstream+authorization%2C+weak+redirect+validation%2C+logged+secrets%2C+and+destructive+tools+without+approval.+Return+a+sequence+diagram+and+one+test+per+finding. "Send to Claude")[Cursor](https://cursor.com/link/prompt?text=Audit+this+remote+MCP+server%27s+authentication+and+authorization+without+making+external+calls.+Trace+one+protected+tools%2Fcall+request+from+401+discovery+through+authorization-server+metadata%2C+client+registration%2C+PKCE%2C+resource+indicators%2C+token+issuance%2C+bearer+validation%2C+audience+checks%2C+scopes%2C+tenant+and+resource+authorization%2C+and+the+upstream+API+request.+Cite+exact+files+and+configuration.+Flag+access+tokens+in+URLs%2C+token+passthrough%2C+missing+audience+validation%2C+broad+upstream+credentials%2C+absent+downstream+authorization%2C+weak+redirect+validation%2C+logged+secrets%2C+and+destructive+tools+without+approval.+Return+a+sequence+diagram+and+one+test+per+finding. "Send to Cursor")[Codex](https://chatgpt.com/codex?prompt=Audit+this+remote+MCP+server%27s+authentication+and+authorization+without+making+external+calls.+Trace+one+protected+tools%2Fcall+request+from+401+discovery+through+authorization-server+metadata%2C+client+registration%2C+PKCE%2C+resource+indicators%2C+token+issuance%2C+bearer+validation%2C+audience+checks%2C+scopes%2C+tenant+and+resource+authorization%2C+and+the+upstream+API+request.+Cite+exact+files+and+configuration.+Flag+access+tokens+in+URLs%2C+token+passthrough%2C+missing+audience+validation%2C+broad+upstream+credentials%2C+absent+downstream+authorization%2C+weak+redirect+validation%2C+logged+secrets%2C+and+destructive+tools+without+approval.+Return+a+sequence+diagram+and+one+test+per+finding. "Send to Codex")[opencode](https://opencode.ai/?q=Audit+this+remote+MCP+server%27s+authentication+and+authorization+without+making+external+calls.+Trace+one+protected+tools%2Fcall+request+from+401+discovery+through+authorization-server+metadata%2C+client+registration%2C+PKCE%2C+resource+indicators%2C+token+issuance%2C+bearer+validation%2C+audience+checks%2C+scopes%2C+tenant+and+resource+authorization%2C+and+the+upstream+API+request.+Cite+exact+files+and+configuration.+Flag+access+tokens+in+URLs%2C+token+passthrough%2C+missing+audience+validation%2C+broad+upstream+credentials%2C+absent+downstream+authorization%2C+weak+redirect+validation%2C+logged+secrets%2C+and+destructive+tools+without+approval.+Return+a+sequence+diagram+and+one+test+per+finding. "Send to OpenCode")
