Skip to content

fix(auth): match complete WWW-Authenticate parameters#3012

Open
tarunag10 wants to merge 4 commits into
modelcontextprotocol:mainfrom
tarunag10:codex/www-auth-param-boundary
Open

fix(auth): match complete WWW-Authenticate parameters#3012
tarunag10 wants to merge 4 commits into
modelcontextprotocol:mainfrom
tarunag10:codex/www-auth-param-boundary

Conversation

@tarunag10

Copy link
Copy Markdown

Summary

  • match WWW-Authenticate auth-param names only at parameter boundaries
  • prevent suffix matches such as error_scope satisfying scope
  • add regressions for scope and resource_metadata prefixed parameters

Test plan

  • uv run pytest tests/client/test_auth.py::TestWWWAuthenticate -q
  • uv run ruff check src/mcp/client/auth/utils.py tests/client/test_auth.py
  • uv run pyright src/mcp/client/auth/utils.py tests/client/test_auth.py
  • git diff --check

Related: #2902

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 2 files

Re-trigger cubic

@tarunag10

Copy link
Copy Markdown
Author

Pushed a follow-up commit (2e2e819) to make the parser quote-aware, not just boundary-aware.

The extractor now splits WWW-Authenticate auth-params on commas only outside quoted strings, then compares auth-param names exactly before returning a value. This preserves the substring-name fix while also avoiding false matches inside quoted values such as realm="api, scope=decoy".

Additional validation added:

  • quoted scope decoy before the real scope
  • quoted-only scope decoy returns None
  • quoted resource_metadata decoy before the real resource_metadata

Validation run locally:

  • uv run pytest tests/client/test_auth.py -k "www_auth" -q — 29 passed
  • uv run ruff format --check src/mcp/client/auth/utils.py tests/client/test_auth.py
  • uv run ruff check src/mcp/client/auth/utils.py tests/client/test_auth.py
  • git diff --check

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 2 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/mcp/client/auth/utils.py">

<violation number="1" location="src/mcp/client/auth/utils.py:69">
P2: `extract_field_from_www_auth` fails to match fields in subsequent `WWW-Authenticate` challenges because the scheme prefix is kept in the parsed parameter name (e.g. `"Bearer scope"`), so valid headers with multiple challenges are misparsed.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Fix all with cubic | Re-trigger cubic

match = re.search(pattern, www_auth_header)
for param in _iter_www_auth_params(www_auth_header):
name, separator, value = param.partition("=")
if separator != "=" or name.strip() != field_name:

@cubic-dev-ai cubic-dev-ai Bot Jun 29, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: extract_field_from_www_auth fails to match fields in subsequent WWW-Authenticate challenges because the scheme prefix is kept in the parsed parameter name (e.g. "Bearer scope"), so valid headers with multiple challenges are misparsed.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/mcp/client/auth/utils.py, line 69:

<comment>`extract_field_from_www_auth` fails to match fields in subsequent `WWW-Authenticate` challenges because the scheme prefix is kept in the parsed parameter name (e.g. `"Bearer scope"`), so valid headers with multiple challenges are misparsed.</comment>

<file context>
@@ -26,14 +64,16 @@ def extract_field_from_www_auth(response: Response, field_name: str) -> str | No
-    match = re.search(pattern, www_auth_header)
+    for param in _iter_www_auth_params(www_auth_header):
+        name, separator, value = param.partition("=")
+        if separator != "=" or name.strip() != field_name:
+            continue
 
</file context>
Fix with cubic

@tarunag10

Copy link
Copy Markdown
Author

Pushed one more test-only follow-up (c05bc04) after the GitHub matrix exposed a coverage-only failure.

The failing jobs had all tests passing, then failed the repo-wide 100% coverage gate because the new quote-aware splitter had untested escaped-character branches. I added a regression for an escaped quote inside a quoted auth-param value, which exercises that branch while preserving the real scope extraction.

Validation run locally:

  • uv run pytest tests/client/test_auth.py -k "www_auth" -q — 30 passed
  • uv run ruff format --check src/mcp/client/auth/utils.py tests/client/test_auth.py
  • uv run ruff check src/mcp/client/auth/utils.py tests/client/test_auth.py
  • git diff --check

@tarunag10

Copy link
Copy Markdown
Author

Pushed another test-only coverage follow-up (32950d8) for the remaining splitter branches.

Added regressions for:

  • a Bearer challenge with no auth-params
  • empty comma segments between auth-params
  • a trailing comma after the final auth-param

Local validation now covers 33 selected auth tests:

  • uv run pytest tests/client/test_auth.py -k "www_auth" -q — 33 passed
  • uv run ruff format --check src/mcp/client/auth/utils.py tests/client/test_auth.py
  • uv run ruff check src/mcp/client/auth/utils.py tests/client/test_auth.py
  • git diff --check

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.

1 participant