fix(auth): coerce empty-string optional URL fields to None in OAuthClientMetadata#2404
fix(auth): coerce empty-string optional URL fields to None in OAuthClientMetadata#2404felixweinberger wants to merge 1 commit intomainfrom
Conversation
There was a problem hiding this comment.
LGTM — clean, well-tested Postel's-law fix that exactly mirrors the existing normalize_token_type pattern in the same file.
Extended reasoning...
Overview
The PR adds a single field_validator on OAuthClientMetadata that coerces empty-string values to None for five optional URL fields (client_uri, logo_uri, tos_uri, policy_uri, jwks_uri). Because OAuthClientInformationFull inherits from OAuthClientMetadata, the coercion automatically covers parsed DCR responses. The diff touches two files: the model definition and its test suite.
Security risks
None. The five fields affected are informational metadata; they are not used in any authentication or authorization decision. The critical redirect_uris field is intentionally excluded. The validator only widens accepted input for values that were previously rejected with a ValidationError (i.e., ""), and the negative-case test confirms that non-empty invalid URLs still raise.
Level of scrutiny
Low. This is a small, non-breaking compatibility shim consistent with the existing normalize_token_type validator already present in the same file. The pattern is idiomatic Pydantic v2 (mode="before", @classmethod). Test coverage is thorough: parametrized per-field, all-at-once, valid-URL passthrough, subclass inheritance, and a negative case.
Other factors
No outstanding reviewer comments; no prior reviews from any reviewer. The bug hunting system found no issues. This is a direct fix for a real-world interoperability problem observed with multiple production OAuth servers.
Coerce
""toNonefor the five OPTIONAL URL fields onOAuthClientMetadataso that DCR responses from servers that echo omitted metadata as empty strings parse successfully.Motivation and Context
RFC 7591 §2 marks
client_uri,logo_uri,tos_uri,policy_uri, andjwks_urias OPTIONAL. Some authorization servers in the wild (observed: Udemy, deepsense.ai, Apify, windsor.ai, firecrawl, and others) echo the client's omitted metadata back as""instead of dropping the keys:{"client_id": "abc123", "client_uri": "", "logo_uri": "", "tos_uri": "", "policy_uri": "", ...}AnyHttpUrlrejects"", sohandle_registration_responseraisesValidationErrorand callers discard an otherwise valid registration — the server returned 201 with a realclient_id.The servers are technically non-compliant (an empty string is not a valid URL), but the only reasonable interpretation of
""for an OPTIONAL field is "absent". This applies Postel's law at the deserialization boundary, matching the existingnormalize_token_typevalidator onOAuthTokenin the same file. BecauseOAuthClientInformationFullinherits fromOAuthClientMetadata, the coercion applies to parsed DCR responses as well.How Has This Been Tested?
New
TestOAuthClientMetadataEmptyUrlCoercioncovers per-field coercion (parametrized over all five fields), all-fields-together, valid-URL passthrough, inheritance throughOAuthClientInformationFull(the DCR-response model), and a negative case confirming non-empty invalid URLs still raise.Breaking Changes
None. This only widens accepted input — previously-rejected
""values now succeed asNone. Valid URLs,None, and omitted keys are unchanged.Types of changes
Checklist
Additional context
RFC 7591 §2: https://datatracker.ietf.org/doc/html/rfc7591#section-2
v1.x backport: #2405