Guide

MCP authorization and OAuth: how sign-in to remote MCP servers works

What MCP authorization is, the four steps of an OAuth sign-in to a remote MCP server, where it goes wrong, and how ContextGate handles it for every AI app at once.

What MCP authorization is

MCP authorization is the part of the Model Context Protocol that says how an AI app proves who it is to a remote MCP server, and on whose behalf it is acting. Since the 2025-06-18 revision of the specification it is built on OAuth 2.1. The MCP server is the OAuth resource server. The AI app (Claude, ChatGPT, Claude Code, Cursor or a gateway acting for them) is the OAuth client. A separate authorization server signs the user in and issues tokens.

Local servers started over stdio do not need any of this: they run as you. Remote servers over HTTP do, because anyone on the internet could otherwise call them. That is why the first request to a remote MCP server so often comes back as 401.

The four steps of a sign-in

01

Discovery

The client makes an unauthenticated request. The server answers 401 with a WWW-Authenticate header that names its protected-resource metadata (RFC 9728). That document names the authorization server, whose own metadata (RFC 8414, or OpenID Connect discovery) lists the endpoints.

In practice

Servers on the older revision publish the authorization-server metadata at their own origin, or simply expose /authorize, /token and /register there. A careful client tries both.

02

Registration

The client registers itself with the authorization server through dynamic client registration (RFC 7591), giving its redirect URI and the grant types it needs: authorization_code and refresh_token. It receives a client ID, and sometimes a client secret.

In practice

Without a registration endpoint there is no automatic sign-in. The server operator has to hand out a client ID by other means.

03

Sign-in

The user is sent to the authorization endpoint with a PKCE challenge (S256), a single-use state value and the MCP server's URL as the resource (RFC 8707). They sign in and consent. The authorization server redirects back with a code.

In practice

The PKCE verifier should never leave the server that generated it, and the state should be signed and expire within minutes so it cannot be replayed.

04

Tokens

The callback exchanges the code, plus the PKCE verifier, for an access token and usually a refresh token. From then on every MCP request carries the access token. When it is close to expiry, the client refreshes it.

In practice

Tokens must only be sent to the server they were issued for. If two processes can refresh at once, refresh under a lock: many servers rotate the refresh token on each use, and a race leaves one process with a dead token.

Static tokens versus OAuth

Many MCP servers still take an API key or bearer token pasted into the AI app's config file. It works, and for a personal server on your own machine it is fine. For anything shared, the differences add up.

Static key in a config fileOAuth sign-in
Where the credential livesPlain text in a config file on each laptopIssued at sign-in, stored by the client, never typed by a person
Who it belongs toWhoever has the fileThe user who signed in
ExpiryNever, unless someone remembersMinutes to hours; refreshed automatically
ScopeUsually everything the key owner can doThe scopes the server asked for and the user consented to
RevocationRotate the key and update every fileRevoke at the authorization server
Shared across appsCopied into Claude, Cursor, Claude Code and so onOne grant per client, or one gateway grant shared by all apps

Where MCP OAuth goes wrong

  • No registration endpoint. The server supports OAuth but not dynamic client registration, so nothing can sign in without a hand-issued client ID. Ask the operator for one, or treat the server as unavailable.
  • No PKCE, or only the plain method. Without S256 an intercepted authorization code can be exchanged by anyone. Refuse to sign in.
  • Tokens sent to the wrong server. A token issued for one MCP server must never be attached to a request to another. Bind tokens to the resource they were issued for.
  • Refresh races. Two instances refresh the same rotating refresh token at the same time; the second one is now signed out. Refresh under a lock.
  • Secrets in the state parameter. The PKCE verifier or a token ends up in a URL, and so in browser history and server logs. Only an opaque id should travel in the state.
  • Tokens in the clear. Access and refresh tokens written to disk unencrypted, or logged with request bodies. Encrypt at rest and keep tokens out of logs.
  • Internal addresses. A server's metadata points the client at a private IP or localhost. In a multi-user deployment, outbound requests should be restricted to public http(s) so a hostile server cannot turn the client into a scanner.

How ContextGate signs in to OAuth-only MCP servers

ContextGate sits between your AI apps and the servers they use: one MCP connection that Claude, ChatGPT, Claude Code, Cursor and the rest share. The AI apps sign in to ContextGate itself with OAuth, in the normal way. For an upstream server that only accepts OAuth, ContextGate is the OAuth client, so the sign-in happens once, for the workspace, instead of once per app per laptop.

  1. A workspace member who may edit connections adds the server as a connection with OAuth sign-in and clicks Sign in.
  2. ContextGate discovers the server's authorization server from its 401 challenge or the well-known metadata paths, with fallbacks for servers on the older revision.
  3. It registers a client for that connection through dynamic client registration, with its own callback URL. If the server has no registration endpoint, it says so and stops. If the server does not support PKCE S256, it refuses to sign in.
  4. The member is sent to the authorization endpoint with a PKCE challenge, a signed single-use state that expires after ten minutes, and the server URL as the resource. The PKCE verifier is stored encrypted and never leaves ContextGate; only an id travels in the state.
  5. The callback exchanges the code. Access and refresh tokens are stored encrypted per workspace, refreshed under a row lock so two instances never race on a rotating refresh token, and only ever sent to the server URL they were issued for. Every request to the server and its authorization server goes through an outbound guard that allows public http(s) only.
  6. The connection is live. From then on every tool call any AI app makes to that server goes through ContextGate, is checked against your policies, and is recorded with its arguments, the redacted result and the outcome.

Servers that take an API key or bearer token are handled too: the key is kept in the workspace, not in a config file on each machine, and the same record and policies apply.

A short checklist before you connect a remote MCP server

  • Does it support OAuth, and if so, dynamic client registration and PKCE S256?
  • What scopes does it ask for, and are they more than your use needs?
  • Where will the tokens or keys live, and who else on the machine can read them?
  • Will every call be recorded somewhere you can read later, with the policy outcome?
  • Can you switch off the tools you do not want used, rather than trusting the model to avoid them?

The wider set of controls is in MCP security best practices. For the app-by-app setup, see how to add one MCP connection to Claude, ChatGPT, Claude Code and Cursor, or browse the MCP servers list.

Questions people ask about MCP authorization

Does MCP use OAuth?

Yes. The MCP authorization specification (revision 2025-06-18) is built on OAuth 2.1. An MCP server that needs sign-in acts as an OAuth resource server, the AI app is the OAuth client, and a separate authorization server issues the tokens. Servers may also accept plain bearer tokens or API keys, but OAuth is the standard path for remote servers.

Why does an MCP server answer 401 with a WWW-Authenticate header?

That is how discovery starts. The header names the server's protected-resource metadata (RFC 9728), which names the authorization server. The client fetches that server's metadata (RFC 8414, or OpenID Connect discovery) to find the authorization, token and registration endpoints.

What is dynamic client registration in MCP?

Dynamic client registration (RFC 7591) lets a client register itself with the authorization server and receive a client ID without anyone filling in a form. MCP relies on it because an AI app cannot be pre-registered with every MCP server in the world. A server without a registration endpoint cannot be signed in to automatically.

What is PKCE and why does MCP require it?

PKCE (Proof Key for Code Exchange) binds the authorization code to the client that requested it: the client sends a hash of a secret with the first request and the secret itself when exchanging the code. MCP requires the S256 method so that a stolen code is useless on its own.

Can I use an API key instead of OAuth with an MCP server?

Often, yes, and many servers only offer that. The trade-off is that a static key in a config file does not expire, is not bound to a user, and is usually shared across every app on the machine. Prefer OAuth where the server offers it, and keep static keys out of config files when it does not.

Where should MCP OAuth tokens be stored?

Encrypted, server-side, and only ever sent to the server they were issued for. Access tokens should be refreshed before they expire, and refresh under a lock if more than one process can refresh at once, because many authorization servers rotate the refresh token on every use.

Ready to see what your AI agents do?

Create a free workspace and add ContextGate to your AI apps in minutes. No card required.

Get started free

We'll email you a sign-in link to set up your workspace.

Rather talk it through first? Book a 30-minute call