-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Server requires authentication but doesn't advertise the auth mechanism #604
Description
Looks like the WWW-Authenticate header is missing.
Command: authprobe scan --llm-max-tokens=1080 --openai-api-key=***REDACTED*** http://localhost:8019/mcp
Scanning: http://localhost:8019/mcp
Scan time: Feb 20, 2026 06:45:16 UTC
Github: https://github.com/authprobe/authprobe
Funnel
[1] MCP probe (401 + WWW-Authenticate) [-] SKIP
auth appears required (initialize returned 401/403)
[2] MCP initialize + tools/list [X] FAIL
initialize -> 401 (error: Unauthorized)
[3] PRM fetch matrix [X] FAIL
PRM unreachable or unusable; OAuth discovery unavailable
[4] Auth server metadata [-] SKIP
no authorization_servers in PRM
[5] Token endpoint readiness (heuristics) [-] SKIP
no token_endpoint in metadata
[6] Dynamic client registration (RFC 7591) [-] SKIP
no registration_endpoint in metadata
Primary Finding (HIGH): AUTH_REQUIRED_BUT_NOT_ADVERTISED (confidence 1.00)
Evidence:
initialize -> 401
initialize error: Unauthorized
WWW-Authenticate: (missing)
PRM unreachable or unusable; OAuth discovery unavailable
Auth appears required but OAuth discovery was not advertised. Next steps: add
WWW-Authenticate + PRM for OAuth/MCP discovery, or document the required non-OAuth auth
(e.g., SigV4).
┌───────────────────────┤ CALL TRACE ├───────────────────────┐
Call Trace Using: https://github.com/authprobe/authprobe
┌────────────┐ ┌────────────┐
│ authprobe │ │ MCP Server │
└─────┬──────┘ └─────┬──────┘
│ │
│ ╔═══ Step 1: MCP probe ═══════╪═══════════════════╗
│ GET http://localhost:8019/mcp
│ Reason: 401 + WWW-Authenticate discovery
│ Accept: text/event-stream
│ Host: localhost:8019
├─────────────────────────────────────────────────────────────────►│
│ 200 OK
│ Access-Control-Allow-Headers: Content-Type, Authorization, Accept, Mcp-Session-Id
│ Access-Control-Allow-Methods: POST, GET, DELETE, OPTIONS
│ Access-Control-Allow-Origin: *
│ Access-Control-Expose-Headers: Mcp-Session-Id
│ Access-Control-Max-Age: 86400
│ Cache-Control: no-cache, no-transform
│ Connection: keep-alive
│ Content-Type: text/event-stream
│ Date: Fri, 20 Feb 2026 06:45:08 GMT
│ Strict-Transport-Security: max-age=31536000; includeSubDomains
│ X-Content-Type-Options: nosniff
│ X-Frame-Options: DENY
│ X-Powered-By: Express
│ X-Xss-Protection: 1; mode=block
│◄─────────────────────────────────────────────────────────────────┤
│ │
│ ╔═══ Step 2: MCP initialize ═══════╪═══════════════════╗
│ POST http://localhost:8019/mcp
│ Reason: Step 2: MCP initialize + tools/list (pre-init tools/list)
│ Accept: application/json, text/event-stream
│ Content-Type: application/json
│ Host: localhost:8019
│ Mcp-Protocol-Version: 2025-11-25
├─────────────────────────────────────────────────────────────────►│
│ 401 Unauthorized
│ Access-Control-Allow-Headers: Content-Type, Authorization, Accept, Mcp-Session-Id
│ Access-Control-Allow-Methods: POST, GET, DELETE, OPTIONS
│ Access-Control-Allow-Origin: *
│ Access-Control-Expose-Headers: Mcp-Session-Id
│ Access-Control-Max-Age: 86400
│ Connection: keep-alive
│ Content-Length: 76
│ Content-Type: application/json; charset=utf-8
│ Date: Fri, 20 Feb 2026 06:45:16 GMT
│ Etag: W/"4c-qMAtz4tDjU5Eupw6k4HTOkiq+do"
│ Keep-Alive: timeout=5
│ Ratelimit-Limit: 20
│ Ratelimit-Policy: 20;w=900
│ Ratelimit-Remaining: 19
│ Ratelimit-Reset: 900
│ Strict-Transport-Security: max-age=31536000; includeSubDomains
│ X-Content-Type-Options: nosniff
│ X-Frame-Options: DENY
│ X-Powered-By: Express
│ X-Xss-Protection: 1; mode=block
│◄─────────────────────────────────────────────────────────────────┤
│ │
│ POST http://localhost:8019/mcp
│ Reason: Step 2: MCP initialize + tools/list (initialize)
│ Accept: application/json, text/event-stream
│ Content-Type: application/json
│ Host: localhost:8019
│ Mcp-Protocol-Version: 2025-11-25
├─────────────────────────────────────────────────────────────────►│
│ 401 Unauthorized
│ Access-Control-Allow-Headers: Content-Type, Authorization, Accept, Mcp-Session-Id
│ Access-Control-Allow-Methods: POST, GET, DELETE, OPTIONS
│ Access-Control-Allow-Origin: *
│ Access-Control-Expose-Headers: Mcp-Session-Id
│ Access-Control-Max-Age: 86400
│ Connection: keep-alive
│ Content-Length: 76
│ Content-Type: application/json; charset=utf-8
│ Date: Fri, 20 Feb 2026 06:45:16 GMT
│ Etag: W/"4c-qMAtz4tDjU5Eupw6k4HTOkiq+do"
│ Keep-Alive: timeout=5
│ Ratelimit-Limit: 20
│ Ratelimit-Policy: 20;w=900
│ Ratelimit-Remaining: 18
│ Ratelimit-Reset: 900
│ Strict-Transport-Security: max-age=31536000; includeSubDomains
│ X-Content-Type-Options: nosniff
│ X-Frame-Options: DENY
│ X-Powered-By: Express
│ X-Xss-Protection: 1; mode=block
│◄─────────────────────────────────────────────────────────────────┤
▼ ▼
┌──────────────────┤ ROOT-CAUSE ANALYSIS ├───────────────────┐
Primary Finding: AUTH_REQUIRED_BUT_NOT_ADVERTISED (High Confidence, High Priority)
Summary of the Finding
The MCP OAuth server responded to an initialize request (Step 2) with HTTP 401 Unauthorized, indicating that authorization is required, yet it did not include a WWW-Authenticate header in the response. In addition, the Protected Resource Metadata (PRM) discovery endpoint was unreachable or returned no usable OAuth metadata (Step 3). This absence of both an authentication challenge (WWW-Authenticate) and OAuth authorization server metadata constitutes a fundamental violation of the OAuth and MCP protocol expectations, resulting in an unsupported authentication flow from the client perspective.
Why This Failure Is Valid and Justified
Relevant Specifications and Requirements
-
MCP 2025-11-25:
- Mandates that when a resource endpoint requires authorization, the server must advertise the authorization method using a
WWW-Authenticateheader on a401 Unauthorizedresponse. This allows clients to understand how to authenticate. - Requires OAuth discovery metadata (PRM) availability to allow clients to dynamically obtain OAuth endpoints (authorization, token, etc.) necessary for interaction.
- Mandates that when a resource endpoint requires authorization, the server must advertise the authorization method using a
-
RFC 8414 (OAuth 2.0 Authorization Server Metadata):
- Specifies that OAuth endpoints must be discoverable via metadata at a well-known URI (PRM).
- This metadata enables clients to understand OAuth server capabilities and endpoints, which is critical for dynamic client registration and authorization flows.
- Without this metadata, clients cannot initiate or continue OAuth authorization.
-
RFC 9728 (OAuth Security Best Practices):
- Requires that
WWW-Authenticateheader must be present with the proper OAuth2 scheme or other defined schemes upon a 401 Unauthorized response to enable clients to identify the authorization requirements. - Servers should not respond with 401 Unauthorized without indicating the required authentication challenge.
- Requires that
-
JSON-RPC 2.0:
- While the underlying transport here is HTTP, JSON-RPC 2.0 expects appropriate transport-layer authentication to be handled correctly to ensure valid client-server communication.
Explanation of the Failure in Context
-
The server's
initializeendpoint responds with HTTP 401 Unauthorized, meaning the resource requires authentication. However, it fails to provide aWWW-Authenticateheader specifying the authentication scheme (e.g., Bearer token for OAuth). This leaves clients unable to determine the method to obtain authorization credentials. -
Attempts to locate OAuth authorization server metadata (PRM) fail because the discovery endpoint is unreachable or returns no valid OAuth data. This means there is no advertised OAuth authorization or token endpoint metadata available, preventing dynamic OAuth flows.
-
The combination of these two failures means:
- Clients see the resource is protected (401) but have no indication of how to authenticate.
- Clients cannot discover OAuth server metadata endpoints to request tokens or perform OAuth interactions.
-
This violates MCP and OAuth best practices because authentication requirement indications and OAuth discovery must be advertised together and coherently for clients to succeed.
What Should Be Changed — Correct Server Behavior
-
Include a
WWW-AuthenticateHeader in 401 Responses- Per RFC 9728 Section 3, upon responding with
401 Unauthorizedindicating OAuth 2.0 bearer token authentication is required, the server must include a header like:WWW-Authenticate: Bearer realm="example", error="invalid_token", error_description="The access token is missing or invalid" - Per MCP 2025-11-25, this header must be present to signal to clients the type of auth expected.
- Per RFC 9728 Section 3, upon responding with
-
Expose OAuth Authorization Server Metadata via PRM
- Per RFC 8414, implement a publicly reachable Protected Resource Metadata endpoint under
.well-known/oauth-protected-resource(PRM), which advertises:authorization_serverstoken_endpointregistration_endpoint(if dynamic registration is supported)
- These endpoints must be advertised over HTTPS URLs to meet transport security requirements (see below).
- Per RFC 8414, implement a publicly reachable Protected Resource Metadata endpoint under
-
Serve All Endpoints over HTTPS with Absolute URLs
- MCP and OAuth metadata must use absolute URLs beginning with
https://for all endpoint URLs (per RFC 3986 and MCP 2025-11-25). - Current evidence shows
http://localhostURLs used, which violates this requirement and can cause clients to malfunction or reject metadata.
- MCP and OAuth metadata must use absolute URLs beginning with
-
Document Non-OAuth Auth If Used
- If the server does not offer OAuth authorization and uses an alternative authentication scheme (e.g., AWS SigV4), it must document this clearly in metadata and include an appropriate
WWW-Authenticateheader describing the scheme, per MCP authorization requirements.
- If the server does not offer OAuth authorization and uses an alternative authentication scheme (e.g., AWS SigV4), it must document this clearly in metadata and include an appropriate
Summary of Correct Server Behavior Example
- Respond to unauthorized requests with: