You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Authorization URL validations required by the OAuth 2.1 specification not implemented #3856
Similar to the existing handling of resource urls OAuth 2.1 requires that URL fragments not be included in the authorization url and that it not contain any of the params used by the authorization request. Neither of these are currently checked for in _perform_authorization_code_grant
The specification also requires that any existing query params are retained, which are not today ( there is an issue open of this particular part of the issue - #2776 ).
Confirmed on main (77001c9), and the failure mode is slightly worse than "not checked": neither check is present, so a query string is not merely dropped, it corrupts the request.
Line 428 builds the URL as f"{auth_endpoint}?{urlencode(auth_params)}", an unconditional question mark. With authorization_endpoint: https://as.example.com/authorize?tenant=acme the result parses as:
So the first authorization parameter is swallowed into the value of the last existing one, and response_type never reaches the authorization server at all. It fails as invalid_request on a compliant server, and any server that defaults response_type to code proceeds with a mangled tenant value.
The fragment case is quieter. https://as.example.com/authorize#frag plus the same parameters yields an empty query and frag?response_type=code&client_id=abc&state=s as the fragment, so the browser sends a request with no parameters and nothing on the client raises.
Why the collision rule matters more here than it looks: should_include_resource_param adds resource whenever protected resource metadata is present or the negotiated version is 2025-06-18 or later, so an endpoint that advertises ?resource= or ?scope= is the case that collides in practice. OAuth 2.1 section 3.1 is explicit on both halves:
"The authorization endpoint URL MUST NOT include a fragment component, and MAY include a query string component, which MUST be retained when adding additional query parameters. The query string component MUST NOT include any parameters defined for use in the authorization request."
An endpoint that violates the third sentence is a metadata document the client must reject. RFC 8707 section 2 also requires the resource value to be an absolute URI and the authorization server applies audience policy on it, so a resource value truncated at the first existing parameter is an audience identifier problem, not a cosmetic URL one.
On placement: validating inside _perform_authorization_code_grant fixes one redirect while leaving the bad metadata in context for the next refresh and the token request. Validating where the authorization server metadata is accepted means a bad document is rejected once, with one error, and the grant stays readable. There is already a precedent for the shape, since validate_resource_url is an injectable callback with a default implementation.
The reassembly itself is small: parse the endpoint, keep its query parameters, reject if any name is in the set the grant is about to add, then rebuild the URL with the merged query instead of interpolating a question mark.
Activity
media-ctrl commentedon Nov 14, 2026
Confirmed on main (77001c9), and the failure mode is slightly worse than "not checked": neither check is present, so a query string is not merely dropped, it corrupts the request.
Line 428 builds the URL as
f"{auth_endpoint}?{urlencode(auth_params)}", an unconditional question mark. Withauthorization_endpoint: https://as.example.com/authorize?tenant=acmethe result parses as:So the first authorization parameter is swallowed into the value of the last existing one, and
response_typenever reaches the authorization server at all. It fails as invalid_request on a compliant server, and any server that defaults response_type to code proceeds with a mangled tenant value.The fragment case is quieter.
https://as.example.com/authorize#fragplus the same parameters yields an empty query and frag?response_type=code&client_id=abc&state=s as the fragment, so the browser sends a request with no parameters and nothing on the client raises.Why the collision rule matters more here than it looks:
should_include_resource_paramadds resource whenever protected resource metadata is present or the negotiated version is 2025-06-18 or later, so an endpoint that advertises?resource=or?scope=is the case that collides in practice. OAuth 2.1 section 3.1 is explicit on both halves:"The authorization endpoint URL MUST NOT include a fragment component, and MAY include a query string component, which MUST be retained when adding additional query parameters. The query string component MUST NOT include any parameters defined for use in the authorization request."
An endpoint that violates the third sentence is a metadata document the client must reject. RFC 8707 section 2 also requires the resource value to be an absolute URI and the authorization server applies audience policy on it, so a resource value truncated at the first existing parameter is an audience identifier problem, not a cosmetic URL one.
On placement: validating inside
_perform_authorization_code_grantfixes one redirect while leaving the bad metadata in context for the next refresh and the token request. Validating where the authorization server metadata is accepted means a bad document is rejected once, with one error, and the grant stays readable. There is already a precedent for the shape, sincevalidate_resource_urlis an injectable callback with a default implementation.The reassembly itself is small: parse the endpoint, keep its query parameters, reject if any name is in the set the grant is about to add, then rebuild the URL with the merged query instead of interpolating a question mark.