Validate the iss authorization-response parameter (RFC 9207 / SEP-2468)#2921
Conversation
The OAuth client now validates the RFC 9207 iss parameter returned on the authorization-response redirect and the issuer of discovered authorization server metadata. iss is compared against the authorization server issuer with simple string comparison (RFC 3986 6.2.1): a mismatch is rejected, and a missing iss is rejected when the server advertised authorization_response_iss_parameter_supported. The callback_handler passed to OAuthClientProvider now returns an AuthorizationCodeResult (code/state/iss) instead of a tuple[str, str | None] so the redirect's iss reaches the validation. AnyHttpUrl appends a trailing slash to a bare authority, which would defeat the byte-exact comparison the spec requires, so the recorded issuer is compared with that lone slash stripped. Flips the auth/metadata-issuer-mismatch conformance scenario green; the auth/iss-* scenarios validate iss correctly but remain baselined because they reach DCR and trip the unimplemented SEP-837 application_type check.
Kludex
left a comment
There was a problem hiding this comment.
Pointers to the substantive logic — the rest of the diff is mostly the mechanical tuple[str, str | None] → AuthorizationCodeResult rename across tests/examples.
…perties - migration.md: spell out that omitting iss raises OAuthFlowError against servers advertising authorization_response_iss_parameter_supported, rather than merely disabling the check. - simple-auth-client example: convert get_state/get_iss to @Property.
With url_preserve_empty_path on the OAuth metadata models (#2925), the issuer parsed from the wire keeps its empty path, so str(oauth_metadata.issuer) is already the byte-exact value the authorization server transmitted. Remove _strip_authority_trailing_slash / raw_issuer and compare directly. This also fixes the false rejection the heuristic introduced for an issuer that genuinely ends in a trailing slash (e.g. Auth0's https://tenant.auth0.com/): its redirect iss now matches its advertised issuer instead of being stripped.
Conformance scenarios this PR addresses (SEP-2468)Run against
The six Both conformance legs pass with no unexpected or stale baseline entries. |
Implements the first item of #2902: validate the RFC 9207
issauthorization-response parameter (SEP-2468).What changed
issquery parameter returned on the authorization-response redirect, and theissuerof discovered authorization server metadata. Comparison is simple string comparison per RFC 3986 §6.2.1 (no normalization): a mismatchedissis rejected, and a missingissis rejected when the AS advertisedauthorization_response_iss_parameter_supported.callback_handlernow returnsAuthorizationCodeResult(code/state/iss) instead oftuple[str, str | None], so the redirect'sissreaches the validation. Breaking change — documented indocs/migration.md.authorization_response_iss_parameter_supportedtoOAuthMetadata.AnyHttpUrlappends a trailing slash to a bare authority (https://as→https://as/), which would defeat the byte-exact comparison the spec requires (iss-supportedmust accepthttps://hostwhileiss-normalizedmust rejecthttps://host/), so the recorded issuer is compared with that lone authority slash stripped.Conformance
Flips
auth/metadata-issuer-mismatchgreen (removed from both expected-failures baselines). Theauth/iss-*scenarios validateisscorrectly but stay baselined because they reach Dynamic Client Registration and trip the unimplemented SEP-837application_typecheck — re-grouped under SEP-837 with accurate comments. Both conformance legs pass with no stale entries.Out of scope (separate PRs, tracked by #2902)
SEP-837 (
application_type), SEP-2350 (scope-union step-up), SEP-2352 (AS migration / credential binding). SEP-2207 (offline_access) is already done.AI Disclaimer
This PR was developed with the assistance of either Claude or Codex. I've reviewed and verified the changes.