2026-07-30T04:32:31.474Z
How Does MCP Authentication Work? Audit the OAuth Chain
Trace the remote MCP OAuth path from the first 401 through resource, issuer, PKCE, scope, token, and readiness receipts.
For a protected remote MCP server, “authentication” is not one token check. It is an authorization chain: the client receives a challenge, discovers metadata for the exact protected resource, discovers and validates an authorization server, obtains a client identity, runs an authorization code flow with PKCE and a resource indicator, receives the required scopes, and proves the resulting token works at the intended MCP endpoint. That answer has an important boundary. The current MCP authorization specification makes authorization optional and applies its OAuth path to HTTP based transports. A local STDIO server should obtain credentials through its host environment or another local mechanism instead. Starting a browser flow for every MCP connection is therefore not a reasonable default. The operational question is not “do I have a token?” It is “which receipts show that every binding in this particular authorization chain agrees?” A token shaped string can coexist with the wrong resource, an untrusted issuer, missing scope, or a protected request that still returns 401 . Start with the transport and the first challenge The official MCP authorization tutorial explains the remote HTTP flow in stages. In condensed form: 1. The client sends an MCP request without a token. 2. The protected MCP server returns 401 Unauthorized with a Bearer WWW Authenticate challenge. 3. The challenge points to protected resource metadata through resource metadata . 4. That metadata identifies the protected resource and one or more authorization servers. 5. The client fetches authorization server metadata and validates the issuer and endpoints. 6. The client obtains a client ID through a mechanism the authorization server supports, then runs the authorization code flow with PKCE and the MCP resource identifier. 7. The client sends the resulting access token to the MCP server and observes the protected request. The first 401 is not a failure to suppress. It is a discovery receipt. A useful record keeps the HTTP status, authentication scheme, metadata URL, observation time, and selected MCP resource. It does not keep the Authorization header, cookies, authorization code, verifier, client secret, or access token. RFC 9728 defines protected resource metadata and the well known discovery pattern. Its security value depends on authority: metadata for https://mcp.example/mcp must describe that resource, not a similar host or a URL supplied by an unrelated service. Following an arbitrary authorization URL from an error body is not equivalent. The authorization server is a separate role. A protected MCP server acts as an OAuth resource server; the MCP client acts as an OAuth client; the authorization server interacts with the user when needed and issues access tokens. Conflating these roles makes a common troubleshooting mistake look plausible: rotating a resource server token before checking whether the client discovered the correct issuer. Bind the resource, issuer, client, and code flow Two URLs deserve exact comparison. The first is the protected resource. RFC 8707 defines the resource request parameter so an authorization server knows the intended recipient of a token. The current MCP draft requires the resource parameter in both authorization and token requests. An access token issued for another API is not “almost valid” for the selected MCP server. The second is the authorization server issuer. Before opening the browser, a client records the issuer from validated authorization server metadata. When an authorization response includes iss , the current MCP draft describes comparison against that recorded value before the client sends the code to a token endpoint. An issuer mismatch is a stop condition, not a reason to try the same code against both endpoints. Client registration is also an explicit layer. A client may use a Client ID Metadata Document, a pre registered client ID, or a supported dynamic registration path. The current draft treats Dynamic Client Registration as a compatibility mechanism rather than a universal assumption. If no supported registration mechanism exists, the correct verdict is registration blocked ; inventing a redirect URI or reusing another product’s client ID would hide the actual interoperability failure. PKCE binds the authorization request to the later code exchange. The audit records only whether the flow retained a bound verifier, never the verifier itself. A missing binding becomes unsafe flow , even if a browser returned a code. Here is the content free shape used for one healthy fixture: Names of scopes are configuration evidence, not secret values. In a sensitive deployment they can still reveal capabilities, so retain only what the health decision needs and apply the same access controls as other operational metadata. Diagnose the first failed layer A flat checklist produces contradictory actions. If protected resource metadata is unavailable, issuer comparison has no trustworthy input. If the resource identifier is wrong, requesting broader scope will not repair it. The classifier therefore uses precedence and stops at the first failed layer: Verdict Evidence that stopped the chain Bounded next action not applicable Local STDIO transport Use the runtime’s local credential mechanism invalid challenge Missing or non HTTPS resource metadata Repair the 401 challenge metadata unavailable Protected resource metadata did not return 200 Restore metadata; do not guess the issuer resource mismatch Metadata or token targets a different resource Correct resource identity or request a resource bound token issuer mismatch Discovered or callback issuer disagrees Reject the flow and investigate metadata authority registration blocked No supported client identity Configure a supported registration mechanism unsafe flow Authorization code flow lacks a PKCE binding Restart with PKCE step up required The current operation needs an ungranted scope Request only the challenged missing scope token rejected Bindings agree, but the protected request still fails Classify the fresh challenge before rotating authorized ready All authorization receipts agree and the request succeeds Continue to MCP initialization and outcome checks The supplied fixture can be replayed without network access: Its dated run produced ten cases, ten first layer verdicts, one authorized ready , and secretFieldsStored: 0 . That result is intentionally stricter than “nine errors and one success.” It proves that the decision rule preserves meaningful differences between a local transport, failed discovery, contradictory identity, unsupported registration, unsafe code flow, missing scope, and rejected token. The first failed layer rule also limits retries. metadata unavailable can justify a bounded metadata retry. issuer mismatch should not. step up required may justify a new consent flow for the challenged scope. token rejected requires reading the new challenge because expiry, revocation, audience, and scope do not share one repair. Keep scope step up separate from token failure The current MCP draft recommends that a server include required scope in its WWW Authenticate challenge. The scope challenged for the current operation is authoritative for that operation; it need not equal the resource metadata’s entire scopes supported set. This changes the operator decision. Suppose a read succeeds with files:read , then a write returns 403 and challenges for files:write . That is not proof that the token store is corrupt. It is a step up required state. The client should ask for the missing permission with human visibility and preserve permissions still needed for other operations. By contrast, a protected request returning 401 after resource, issuer, registration, PKCE, and scope receipts agree is token rejected . The safe next step is to classify the fresh challenge. Repeatedly presenting the same token is activity, not progress. Rotating every credential can also destroy useful evidence and interrupt healthy clients. An authorized ready verdict remains narrow. It says the remote MCP server accepted the authorization chain for this request. It does not say: MCP initialization and capability negotiation succeeded; the selected tool still exists or its schema is unchanged; a tool call produced the intended external effect; a side effect is safe to retry after a timeout; the user’s deliverable exists; the authorization server, client, and resource are globally trustworthy. Those are subsequent health and security decisions. A successful protected request should move the run into MCP lifecycle checks, then tool effect and outcome verification—not directly to “agent healthy.” Use the receipt without collecting credentials For production operations, store hashes or stable IDs for the selected client and resource only when they are needed to correlate events. Record timestamps and specification version because metadata and protocol rules evolve. Keep the raw token, code, verifier, secret, cookie, prompt, tool arguments, and tool results out of the health record. The artifact is a classifier, not a live conformance suite. It trusts the observations supplied to it. A real implementation must additionally validate TLS, metadata origin, redirect URIs, issuer behavior, token signatures or introspection, audience, expiry, and deployment policy. The MCP draft was checked on July 30, 2026; pin the specification you implement and rerun the fixture when that contract changes. Sidewisp’s intended product territory includes tool reachability, expired credentials, permission loss, useful progress, and outcome verification. Sidewisp is currently in private preview. Its production monitoring adapters and recovery executor are not generally shipped, so this article provides an independent operating rule rather than claiming that Sidewisp already performs this MCP authorization audit. The practical answer to “how does MCP authentication work?” is therefore a chain of authorization receipts, not a bearer token screenshot. Treat the first contradiction as the diagnosis, apply one bounded repair, and keep authorization success separate from tool success and the user’s final outcome.