MCP now requires OAuth 2.1 on HTTP servers: what breaks in production
The official Model Context Protocol specification, revised in June 2025, makes a specific OAuth 2.1 flow mandatory for servers exposed over HTTP. Anyone who connected agents to Supabase, Convex, or internal APIs through simpler shortcuts needs to review how tokens flow.

The official Model Context Protocol specification, revised in June 2025, makes a specific OAuth 2.1 flow mandatory for servers exposed over HTTP. Anyone who connected agents to Supabase, Convex, or internal APIs through simpler shortcuts needs to review how tokens flow.
What the specification has required since June 2025 (and what remains optional)
The official Model Context Protocol specification dedicates an entire section to authorization in the revision published on June 18, 2025. The text makes clear, right at the start, that supporting authorization remains optional for any MCP implementation. The catch for anyone already running a server in production comes in the next paragraph: once an implementation runs over HTTP transport and decides to support authorization, it must follow exactly this OAuth 2.1-based flow, not a simplified or homegrown version of it.
The same section explicitly exempts the STDIO transport: local servers, invoked by a child process (the common case of someone testing an MCP server via npx or uv run inside Claude Desktop or a custom agent), should not follow this specification and instead pull credentials from the environment, such as a variable in .env. Most prototypes that run only on the laptop, without an exposed port, fall outside this change. The problem shows up when that same server leaves the laptop and starts serving multiple agents over HTTP, a typical case of integration with Supabase, Convex, or an internal company API.
| Transport | Specification requirement | How it authenticates |
|---|---|---|
| STDIO (local process) | Should not follow this authorization flow | Credentials via environment variable |
| HTTP (remote, multi-user server) | Must implement full OAuth 2.1 with the listed RFCs | Bearer token validated on every request |
The mismatch that catches production servers off guard
For an HTTP server that decides to support authorization, the specification ties together four IETF standards in a mandatory sequence. An MCP server built before June 2025 with a simple Authorization: Bearer <fixed-key> is unlikely to meet all of them, even if the authentication itself works.
- RFC 9728 (Protected Resource Metadata): the MCP server must publish a document stating where the authorization server is, listed in the
authorization_serversfield. - RFC 8414 (Authorization Server Metadata): the authorization server must expose its own endpoints in a discoverable way.
- RFC 7591 (Dynamic Client Registration): client and authorization server should support automatic
client_idregistration, without manual friction. - RFC 8707 (Resource Indicators): every token request must include the
resourceparameter with the MCP server's canonical URI, binding the token to that specific destination.
In practice, this changes the error response the server returns. Instead of a bare 401, the specification requires the WWW-Authenticate header pointing to the metadata:
Editor's note: the code in this section was not run in a real environment. Validate it before using in production.
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer resource_metadata="https://mcp.example.com/.well-known/oauth-protected-resource"An MCP client written before this revision, which only knew how to treat a 401 as "ask for the key again," doesn't know how to follow this header or discover the authorization server on its own. It simply stops authenticating, with no clear error message for whoever is debugging.
The pattern the specification prohibits: passing the token through
A common shortcut in quick MCP implementations over Supabase or Convex is to take the session token the client already has (the JWT issued by Supabase's GoTrue, for example) and simply forward it, unchanged, to the upstream API when handling the tool call. It works in local testing and slips by unnoticed in production, until someone reads the specification's security section.
If the MCP server makes requests to upstream APIs, it may act as an OAuth client to them. The access token used at the upstream API is a separate token, issued by the upstream authorization server. The MCP server MUST NOT pass through the token it received from the MCP client.
Model Context Protocol specification, revision 2025-06-18
The reason is the so-called "confused deputy" problem: the downstream API (Supabase, Convex, or the internal system) never validated that the token went through the MCP server's correct flow, and a token leaked in the server's logs is worth as much as the master key. The specification goes further and requires proxy servers using a static client_id to obtain explicit user consent for each dynamically registered MCP client, before forwarding anything to the third-party authorization server.
What the compliance roadmap looks like
For anyone who needs to bring an existing HTTP server into compliance with the specification, the path it describes roughly follows this sequence:
- Publish the Protected Resource Metadata document at
/.well-known/oauth-protected-resource, with theauthorization_serversfield filled in. - Replace any bare
401with a401carrying theWWW-Authenticateheader pointing to that metadata URL. - Point to an authorization server, either your own or a third-party one (Auth0, Clerk, WorkOS, or Supabase's own auth provider), that exposes metadata via RFC 8414 and, ideally, Dynamic Client Registration via RFC 7591.
- Require and validate the
resourceparameter in token requests, binding the token to the MCP server's canonical URI, not to the upstream API. - Exchange the client's token for one of your own before calling Supabase, Convex, or the internal API, instead of passing through the received Bearer token unchanged.
- Implement PKCE on the client and prefer short-lived tokens, with refresh token rotation for public clients.
In a typical project that already uses a managed identity provider, items 3 and 6 tend to already be handled by the platform; items 1, 2, and 5 are usually the real coding work on the MCP server.
When migration can wait
Servers that only serve over STDIO, inside a local development tool, don't need any of this: the specification itself exempts them and points to environment credentials. Internal agents running behind a VPN, consumed only by a closed group of people within the same company, can also prioritize other things first, as long as no one plans to open that server to third-party MCP clients.
The trade-off is interoperability: more and more MCP clients (from commercial assistants to open-source agent frameworks) already expect to find RFC 9728 metadata and will fail silently against a server that only understands a fixed token. One point the specification itself leaves open is the choice among multiple authorization_servers listed in the metadata: the responsibility for deciding which one to use is explicitly left to the client, with no standard criterion defined.
Translated from the Brazilian Portuguese original · Read the original
IBM's Granite Switch 4.1 brings chat, decisions, and speech together in a single endpoint
IBM combines the ability to converse, classify, and transcribe audio in a single model, using lightweight adapters that share the same GPU cache.





