From af6489593ea8bb121d123c11c3a84ebce1f849e6 Mon Sep 17 00:00:00 2001 From: Felix Weinberger <3823880+felixweinberger@users.noreply.github.com> Date: Tue, 23 Jun 2026 12:44:29 +0100 Subject: [PATCH] =?UTF-8?q?fix(auth):=20make=202025-03-26=20backcompat=20m?= =?UTF-8?q?ock=20RFC=208414=20=C2=A73.3-compliant=20(#359)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(auth): make 2025-03-26 backcompat mock RFC 8414 §3.3-compliant Drop the routePrefix from auth/2025-03-26-oauth-metadata-backcompat. The prefix caused createAuthServer to report issuer:'/oauth' while serving the metadata at the root /.well-known/oauth-authorization-server — an RFC 8414 §3.3 mismatch a conforming client must reject. The MCP server in this scenario only mounts /mcp, so the unprefixed /authorize, /token, /register routes do not collide (the sibling endpoint-fallback scenario already mounts them at root). The scenario continues to test exactly what it's meant to: 2025-03-26-spec discovery with no PRM, OAuth metadata at the root well-known path. * fix(auth): keep /oauth prefix in 2025-03-26 backcompat, override issuer instead Dropping routePrefix made the metadata-advertised endpoints land on the 2025-03-26 hardcoded fallback paths, so a client that fetches the well-known doc but ignores its body would now pass. Restore the prefix and pin the metadata issuer to the bare origin via a lazy metadataIssuer override so the mock is RFC 8414 §3.3-compliant without losing the fallback-vs-metadata distinction. --------- Co-authored-by: Paul Carleton --- src/scenarios/client/auth/helpers/createAuthServer.ts | 9 +++++++-- src/scenarios/client/auth/march-spec-backcompat.ts | 8 ++++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/scenarios/client/auth/helpers/createAuthServer.ts b/src/scenarios/client/auth/helpers/createAuthServer.ts index d7d1fc4..4dde479 100644 --- a/src/scenarios/client/auth/helpers/createAuthServer.ts +++ b/src/scenarios/client/auth/helpers/createAuthServer.ts @@ -59,8 +59,10 @@ export interface AuthServerOptions { * Override the `issuer` value served in the AS metadata document. Used to * test that clients validate the metadata issuer against the issuer * identifier used to construct the well-known URL (RFC 8414 §3.3). + * Accepts a lazy getter for callers that don't know the server URL until + * after `start()`. */ - metadataIssuer?: string; + metadataIssuer?: string | (() => string); tokenVerifier?: MockTokenVerifier; onTokenRequest?: (requestData: { scope?: string; @@ -156,7 +158,10 @@ export function createAuthServer( }); const metadata: any = { - issuer: metadataIssuer ?? `${getAuthBaseUrl()}${routePrefix}`, + issuer: + typeof metadataIssuer === 'function' + ? metadataIssuer() + : (metadataIssuer ?? `${getAuthBaseUrl()}${routePrefix}`), authorization_endpoint: `${getAuthBaseUrl()}${authRoutes.authorization_endpoint}`, token_endpoint: `${getAuthBaseUrl()}${authRoutes.token_endpoint}`, ...(!disableDynamicRegistration && { diff --git a/src/scenarios/client/auth/march-spec-backcompat.ts b/src/scenarios/client/auth/march-spec-backcompat.ts index 3e54388..48f9170 100644 --- a/src/scenarios/client/auth/march-spec-backcompat.ts +++ b/src/scenarios/client/auth/march-spec-backcompat.ts @@ -25,8 +25,12 @@ export class Auth20250326OAuthMetadataBackcompatScenario implements Scenario { const authApp = createAuthServer(ctx, this.checks, this.server.getUrl, { // Disable logging since the main server will already have logging enabled loggingEnabled: false, - // Add a prefix to auth endpoints to avoid being caught by auth fallbacks - routePrefix: '/oauth' + // Keep auth endpoints off the 2025-03-26 fallback paths so a client that + // fetches metadata but ignores the advertised endpoints still 404s. + routePrefix: '/oauth', + // Metadata is served at the root well-known path, so per RFC 8414 §3.3 + // the `issuer` must be the bare origin — not `/oauth`. + metadataIssuer: () => this.server.getUrl() }); const app = createServer( ctx,