Skip to content

fix: include resource_metadata in all 401 WWW-Authenticate responses#3993

Open
ecthelion77 wants to merge 1 commit intoIBM:mainfrom
forterro:fix/oauth-resource-metadata-upstream
Open

fix: include resource_metadata in all 401 WWW-Authenticate responses#3993
ecthelion77 wants to merge 1 commit intoIBM:mainfrom
forterro:fix/oauth-resource-metadata-upstream

Conversation

@ecthelion77
Copy link
Copy Markdown
Contributor

🐛 Bug-fix PR

📌 Summary

When a client sends an empty Authorization: Bearer header to an OAuth-enabled server, the 401 response's WWW-Authenticate header is missing the resource_metadata attribute (RFC 9728). This prevents MCP clients (Open WebUI, VS Code) from discovering the OAuth authorization server to initiate the flow.

The root cause is that the empty-bearer check in _auth_no_token() fires before the per-server OAuth enforcement, returning a generic Bearer without the resource_metadata URL.

Fixes #3990

🔁 Reproduction Steps

  1. Configure a gateway with a backend MCP server that has oauth_enabled=true
  2. Send a request with an empty Authorization: Bearer header (or Authorization: Bearer with trailing space)
  3. Observe the 401 response: WWW-Authenticate: Bearer — missing resource_metadata
  4. MCP client cannot discover the OAuth flow and authentication fails

🐞 Root Cause

In _auth_no_token(), the empty-bearer check (bearer_header_supplied) runs before _check_server_oauth_enforcement(). When the client sends an empty Bearer header to an OAuth-enabled server, the function returns early with a generic WWW-Authenticate: Bearer that lacks the resource_metadata attribute.

The strict-mode check (mcp_require_auth) also uses a hardcoded "Bearer" string without resource_metadata.

💡 Fix Description

  1. Initialize www_auth = "Bearer" at the top of _auth_no_token()
  2. Run the per-server OAuth enforcement check first — if the server requires OAuth, OAuthRequiredError is raised and handled with full resource_metadata (unchanged behavior)
  3. Move the empty-bearer check and strict-mode check after the per-server enforcement, using the www_auth variable instead of hardcoded "Bearer"

This ensures that:

  • OAuth-enabled servers always return resource_metadata in their 401 responses (via OAuthRequiredError handler)
  • Non-OAuth servers continue to return generic Bearer (unchanged)
  • The strict-mode check now also benefits from www_auth propagation

The change is a pure reordering — no new logic, no new code paths. Line count: +11/−11.

🧪 Verification

Check Command Status
Lint suite make lint ⚠️ Not run (no local dev env)
Unit tests make test ⚠️ Not run (no local dev env)
Coverage ≥ 80 % make coverage ⚠️ Not run (no local dev env)
Manual regression no longer fails Tested in production (Kubernetes) for 3+ weeks with multiple OAuth providers (Microsoft Graph, Freshservice) — clients correctly discover OAuth flow via resource_metadata

📐 MCP Compliance (if relevant)

  • Matches current MCP spec (RFC 9728 resource_metadata in WWW-Authenticate)
  • No breaking change to MCP clients

✅ Checklist

  • Code formatted
  • No secrets/credentials committed
  • DCO Signed-off-by included

@ecthelion77 ecthelion77 force-pushed the fix/oauth-resource-metadata-upstream branch from b2ca5b6 to 3dbb6b2 Compare April 13, 2026 10:25
@ecthelion77
Copy link
Copy Markdown
Contributor Author

Suggested labels: bug, SHOULD, python, mcp-protocol, security

@ecthelion77 ecthelion77 force-pushed the fix/oauth-resource-metadata-upstream branch from 3dbb6b2 to 27772c3 Compare April 14, 2026 12:46
@ecthelion77 ecthelion77 force-pushed the fix/oauth-resource-metadata-upstream branch 2 times, most recently from 74fd9d3 to f74e717 Compare April 14, 2026 15:35
…auth

Signed-off-by: Olivier Gintrand <olivier.gintrand@forterro.com>
@ecthelion77 ecthelion77 force-pushed the fix/oauth-resource-metadata-upstream branch from f74e717 to 68b5341 Compare April 14, 2026 15:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG]: OAuth 401 responses missing resource_metadata in WWW-Authenticate when server requires OAuth

2 participants