Skip to content

fix: normalize OAuth redirect URI URL subtypes#2953

Closed
fengjikui wants to merge 1 commit into
modelcontextprotocol:mainfrom
fengjikui:codex/oauth-redirect-uri-url-subtypes
Closed

fix: normalize OAuth redirect URI URL subtypes#2953
fengjikui wants to merge 1 commit into
modelcontextprotocol:mainfrom
fengjikui:codex/oauth-redirect-uri-url-subtypes

Conversation

@fengjikui

Copy link
Copy Markdown

Summary

Fixes #2687 by normalizing OAuthClientMetadata.redirect_uris entries at the model boundary. If callers pass a Pydantic URL subtype such as AnyHttpUrl, the value is revalidated through the declared AnyUrl field type instead of being stored as the stricter subtype.

Root cause

Pydantic v2 URL equality is type-strict. A stored AnyHttpUrl("https://example.com/callback") and an incoming AnyUrl("https://example.com/callback") serialize to the same string, but compare non-equal. That makes validate_redirect_uri() reject a registered redirect URI during OAuth flows.

Changes

  • Added a redirect_uris field validator that stringifies existing AnyUrl instances before Pydantic validates the field.
  • Added regression coverage for OAuthClientInformationFull(redirect_uris=[AnyHttpUrl(...)]) validating an incoming equivalent AnyUrl(...).
  • Kept JSON serialization unchanged and still reject unrelated redirect URIs.

Validation

  • uv run pytest tests/shared/test_auth.py::test_redirect_uri_subtypes_normalized_for_validation -q failed before the fix with InvalidRedirectUriError.
  • uv run ruff format --check src/mcp/shared/auth.py tests/shared/test_auth.py
  • uv run ruff check src/mcp/shared/auth.py tests/shared/test_auth.py
  • uv run pytest tests/shared/test_auth.py tests/client/test_auth.py tests/interaction/auth/test_authorize_token.py -q -> 155 passed, 1 xfailed
  • git diff --check

@maxisbey maxisbey closed this Jun 23, 2026
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.

OAuthClientInformationFull.redirect_uris: pydantic strict-type-equality breaks AnyUrl(x) != AnyHttpUrl(x) round-trip

2 participants