{"record":{"id":"54a44baa538369d4","repo":"different-ai/openwork","slug":"auth-resource-discovery","errorCode":"AUTH_RESOURCE_DISCOVERY","errorMessage":"Unauthenticated MCP probe returned HTTP ${challengeResponse.status}, not 401","messagePattern":"Unauthenticated MCP probe returned HTTP (.+?), not 401","errorType":"exception","errorClass":"ProbeFailure","httpStatus":null,"severity":"error","filePath":"packages/enterprise-mcp-mock-server/src/testing/probe.ts","lineNumber":522,"sourceCode":"          origin: baseUrl.origin,\n        },\n        body: JSON.stringify({\n          jsonrpc: \"2.0\",\n          id: 0,\n          method: \"initialize\",\n          params: {\n            protocolVersion: scenario.protocol.version,\n            capabilities: {},\n            clientInfo: { name: \"enterprise-mcp-probe\", version: \"0.1.0\" },\n          },\n        }),\n      },\n      \"AUTH_RESOURCE_DISCOVERY\",\n      overallDeadline,\n    )\n    await discardResponseBody(challengeResponse, \"AUTH_RESOURCE_DISCOVERY\", \"oauth_discovery_resource\")\n    if (challengeResponse.status !== 401) {\n      throw new ProbeFailure(\"AUTH_RESOURCE_DISCOVERY\", \"oauth_discovery_resource\", `Unauthenticated MCP probe returned HTTP ${challengeResponse.status}, not 401`)\n    }\n    const challengeHeader = challengeResponse.headers.get(\"www-authenticate\") ?? \"\"\n    const metadataMatch = /resource_metadata=\"([^\"]+)\"/.exec(challengeHeader)\n    const metadataUrlValue = metadataMatch?.[1]\n    if (!metadataUrlValue) {\n      throw new ProbeFailure(\"AUTH_RESOURCE_DISCOVERY\", \"oauth_discovery_resource\", \"MCP 401 challenge did not provide resource_metadata\")\n    }\n    const resourceMetadataUrl = assertPinnedOrigin(metadataUrlValue, baseUrl, \"AUTH_RESOURCE_DISCOVERY\")\n    const expectedMetadataPath = `/.well-known/oauth-protected-resource${profile.endpointPath}`\n    if (resourceMetadataUrl.pathname !== expectedMetadataPath) {\n      throw new ProbeFailure(\"AUTH_RESOURCE_DISCOVERY\", \"oauth_discovery_resource\", \"MCP challenge pointed to unexpected protected-resource metadata\")\n    }\n    const resourceResponse = await expectOk(\n      await fetchStep(resourceMetadataUrl, undefined, \"AUTH_RESOURCE_DISCOVERY\", overallDeadline),\n      \"AUTH_RESOURCE_DISCOVERY\",\n    )\n    const resourceMetadata = parseAt(\n      protectedResourceMetadataSchema,","sourceCodeStart":504,"sourceCodeEnd":540,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/packages/enterprise-mcp-mock-server/src/testing/probe.ts#L504-L540","documentation":"The probe first hits the MCP endpoint unauthenticated and requires the OAuth-protected-resource discovery handshake: the server MUST respond 401 so the client can learn the resource metadata from WWW-Authenticate. Any other status means the auth challenge contract is broken, so the probe fails in AUTH_RESOURCE_DISCOVERY with subcode oauth_discovery_resource.","triggerScenarios":"The unauthenticated GET/POST probe of the MCP endpoint returns 200 (no auth enforced), 403 (rejected without challenge), 302 (redirected to a login page), or 500 instead of 401.","commonSituations":"Server misconfigured to serve the MCP endpoint without auth, a middleware returning 403 Forbidden instead of 401 Unauthorized, or auth handled by a UI redirect rather than a 401 challenge.","solutions":["Configure the MCP endpoint to return HTTP 401 with a WWW-Authenticate header for requests lacking a Bearer token.","Replace 403 responses on unauthenticated access with 401 per RFC 6750 / MCP auth spec.","Disable login-page redirects for the MCP route so API clients receive the 401 challenge.","Verify auth middleware ordering so the challenge runs before other handlers can return 200/500."],"exampleFix":"// before\nif (!token) return res.status(403).json({ error: \"forbidden\" })\n// after\nif (!token) return res.status(401).set(\"www-authenticate\", `Bearer resource_metadata=\"${metadataUrl}\"`).end()","handlingStrategy":"validation","validationCode":"const res = await fetch(mcpUrl)\nif (res.status !== 401) throw new Error(`Unauthenticated MCP request must return 401, got ${res.status}`)\nif (!res.headers.get(\"www-authenticate\")) throw new Error(\"Missing WWW-Authenticate challenge header\")","typeGuard":null,"tryCatchPattern":"try {\n  const result = await probeEnterpriseMcpMockServer({ baseUrl })\n} catch (e) {\n  if (e instanceof ProbeFailure && e.phase === \"AUTH_RESOURCE_DISCOVERY\") {\n    console.error(\"Server did not issue a proper 401 OAuth challenge:\", e.message)\n  } else throw e\n}","preventionTips":["Return 401 (never 403 or a redirect) for unauthenticated MCP requests","Verify auth middleware order so the challenge is emitted before other handlers","Add a unit test asserting an unauthenticated request yields 401 + WWW-Authenticate"],"tags":["oauth","http","auth","mcp"],"backgroundTag":"missing-www-authenticate-challenge","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}