Skip to content
Muhammad Moeed

MCP Authentication Explained: Secure Your Remote MCP Server

Understand MCP authentication with a simple example. Learn how OAuth login, access tokens, scopes, and server checks protect a remote MCP server.

MCP authentication helps a remote MCP server check who is asking to use its tools. Authorization decides what that caller is allowed to do. You need both when those tools can access private data.

If those words are new, start with this example: you want an AI assistant to read your calendar. You are happy for it to list meetings. You do not want it to delete them.

The connection needs a way to identify your account and allow reading without also allowing deletion. This guide explains that flow, one step at a time.

What is an MCP server?

MCP, short for Model Context Protocol, is a standard way for AI applications to connect to tools and data.

In our example, the MCP server offers tools such as list_meetings and create_meeting. The AI application’s MCP client sends requests to that server.

A remote server runs at a network address, such as https://calendar.example.com/mcp. This guide focuses on protected remote HTTP servers. A local server launched through standard input and output has a different security setup.

If you have not built a tool yet, the first MCP server tutorial covers that starting point.

Authentication and authorization: what is the difference?

TermQuestion it answersCalendar example
AuthenticationWho is signing in?This is Sara’s account
AuthorizationWhat access is allowed?The assistant may read Sara’s meetings
Access tokenWhat does the client present on a request?A credential representing the granted access
ScopeWhich category of action is allowed?calendar:read

OAuth handles delegated authorization: letting an application act with limited permission. Signing in happens through the authorization server’s login system. OAuth itself is not an identity protocol; OpenID Connect is commonly used when an application also needs standardized identity information.

The MCP authorization specification describes the client, protected server, and authorization server as separate roles. They do not all need separate hosting, but their responsibilities stay distinct.

How does MCP authentication work?

For a typical browser-based connection, the flow is:

  1. The client contacts the protected MCP server.
  2. The server points it to metadata describing where authorization happens.
  3. The client opens a browser so the user can sign in and approve access.
  4. The client completes the authorization-code exchange and obtains an access token.
  5. It sends that token with requests to the MCP server.
  6. The server checks the token and the requested action before returning private data.

The discovery details are defined in the MCP authorization specification. A compatible OAuth library should handle them; you should not need to build the protocol from scratch.

What does the token look like on a request?

This is an illustrative HTTP header, with a fake value:

Authorization: Bearer EXAMPLE_TOKEN_NOT_A_REAL_SECRET

A bearer token can be used by whoever possesses it. Keep it out of URLs, screenshots, and logs, and use HTTPS for remote connections. These rules come from RFC 6750, bearer token usage.

What is PKCE?

You may see PKCE, pronounced “pixy,” in setup instructions. It ties the authorization-code exchange to the client that started it. Someone who intercepts the code should not be able to exchange it without the matching verifier.

Let the OAuth client library create and check these values. RFC 7636 explains the mechanism.

A worked example: read meetings without allowing changes

Suppose your server offers two tools:

ToolRequired scopeAdditional check
list_meetingscalendar:readUser can access the requested calendar
create_meetingcalendar:writeUser can change the requested calendar

Sara approves reading. The server receives a valid token with calendar:read. A request to list her meetings succeeds.

If the assistant later tries to create a meeting, the server must reject that action unless write permission has also been granted. The client may offer a new consent step, but the server should not silently add permission.

There is another check: a read scope does not mean access to every customer’s calendar. If the request names someone else’s calendar, the application must check Sara’s access to that specific calendar.

Here is a small JavaScript illustration of that final application check:

// Illustration only: this is not token-validation middleware.
// `auth` must come from trusted middleware after token verification.
function canReadCalendar(auth, calendar) {
  return (
    auth.scopes.includes("calendar:read") &&
    auth.userId === calendar.ownerId
  );
}

This example assumes private calendars with one owner. A real shared-calendar app needs its own membership rules. Never fill auth.userId from a user-supplied tool argument.

What must the server check?

Use a maintained library to validate tokens. The server needs to establish that a token is valid, unexpired, issued by a trusted authority, and intended for this server. Then check the required permissions.

Some tokens are signed JWTs; others are opaque strings checked through the issuer. Merely decoding a JWT does not verify it.

Do not accept an unrelated service’s token and pass it through as if it granted access to your MCP server. When your server calls another API, manage that upstream authorization separately. The MCP security guidance explains token passthrough and related risks.

Finally, check the user’s access to the specific record on every sensitive tool call. Login does not replace application permissions.

Using Cloudflare Workers OAuth Provider

Cloudflare’s Workers OAuth Provider v1 announcement introduces a split setup:

  • An authorization Worker manages sign-in and token issuance.
  • An MCP Worker checks tokens and serves tools.
  • A Service Binding lets the Workers communicate without making that call over the public Internet.

The package provides OAuthAuthorizationServer and OAuthResourceServer. It also supports asking for extra scopes through insufficientScope().

For a first implementation, follow the complete example linked in Cloudflare’s announcement. Configure your own resource URL, login and consent flow, scopes, and Worker binding. A small copied middleware fragment is not a complete login system.

One implementation detail deserves care: select permission based on the MCP tool being called, not only the HTTP method. Read tools can also be invoked through HTTP POST. A POST request does not automatically mean “change data.”

Why does my MCP server return 401 or 403?

ResultLikely meaningWhat to check
401 UnauthorizedNo usable tokenToken expiry, trusted issuer, intended resource, and discovery setup
403 with insufficient_scopeToken lacks a required permissionRequested scopes and approved consent
An application permission errorUser cannot access this recordOwnership, team membership, or tenant rules
Login keeps repeatingThe authorization flow is not completingRedirect URL, client configuration, and safe server logs

The HTTP bearer-token meanings are described in RFC 6750. Exact error messages depend on your library. A tool-level permission failure may be returned as an MCP error rather than an HTTP 403.

Do not debug these problems by posting a real token. Share the status, a redacted error, and the relevant configuration instead.

What should you test before launch?

Run these cases with test accounts:

  1. No token: private tools remain unavailable.
  2. Expired token: access fails.
  3. Token intended for another server: access fails.
  4. Read-only access: listing works, creating fails.
  5. Another user’s record ID: access fails unless sharing explicitly allows it.
  6. Logs: no tokens or private record contents appear unexpectedly.

These tests check separate promises. Passing the login test alone does not prove that your permissions are correct.

Common questions

Does every MCP server need a login screen?

No. A public tool that returns public information may not need user authorization. A remote tool handling private accounts needs an appropriate access-control design. Local process-based tools are a different case.

Can I use one shared API key for all customers?

It would make individual access and revocation difficult to manage. For an app acting for different users, use a design that preserves each user’s identity and permissions.

Does connecting an MCP server make its tools safe?

No. Authorization controls access; it does not prove that every tool action is appropriate. Also review tool permissions and how sensitive actions are approved.

Continue with protecting API keys from coding agents, the MCP security guide, or the MCP articles.