Add passthrough_authorization_parameters support to OIDC configuration (#18232)

# Add passthrough_authorization_parameters support to OIDC configuration

This PR adds `the passthrough_authorization_parameters` option to OIDC
configuration, allowing specific query parameters (like `login_hint`) to
be passed from the redirect endpoint to the authorization grant URL.

This enables clients to provide additional context to identity providers
during authentication flows.

# Pull Request Checklist

<!-- Please read
https://element-hq.github.io/synapse/latest/development/contributing_guide.html
before submitting your pull request -->

* [x] Pull request is based on the develop branch
* [x] Pull request includes a [changelog
file](https://element-hq.github.io/synapse/latest/development/contributing_guide.html#changelog).
The entry should:
- Be a short description of your change which makes sense to users.
"Fixed a bug that prevented receiving messages from other servers."
instead of "Moved X method from `EventStore` to `EventWorkerStore`.".
  - Use markdown where necessary, mostly for `code blocks`.
  - End with either a period (.) or an exclamation mark (!).
  - Start with a capital letter.
- Feel free to credit yourself, by adding a sentence "Contributed by
@github_username." or "Contributed by [Your Name]." to the end of the
entry.
* [x] [Code
style](https://element-hq.github.io/synapse/latest/code_style.html) is
correct
(run the
[linters](https://element-hq.github.io/synapse/latest/development/contributing_guide.html#run-the-linters))

---------

Co-authored-by: Quentin Gliech <quenting@element.io>
This commit is contained in:
Olivier D
2025-04-10 15:39:27 +02:00
committed by GitHub
parent 081f6ad50f
commit dd05cc55ee
5 changed files with 48 additions and 1 deletions

View File

@@ -0,0 +1 @@
Add `passthrough_authorization_parameters` in OIDC configuration to allow to pass parameters to the authorization grant URL.

View File

@@ -3672,6 +3672,9 @@ Options for each entry include:
* `additional_authorization_parameters`: String to string dictionary that will be passed as
additional parameters to the authorization grant URL.
* `passthrough_authorization_parameters`: List of parameters that will be passed through from the redirect endpoint
to the authorization grant URL.
* `allow_existing_users`: set to true to allow a user logging in via OIDC to
match a pre-existing account instead of failing. This could be used if
switching from password logins to OIDC. Defaults to false.
@@ -3798,6 +3801,7 @@ oidc_providers:
jwks_uri: "https://accounts.example.com/.well-known/jwks.json"
additional_authorization_parameters:
acr_values: 2fa
passthrough_authorization_parameters: ["login_hint"]
skip_verification: true
enable_registration: true
user_mapping_provider:

View File

@@ -356,6 +356,9 @@ def _parse_oidc_config_dict(
additional_authorization_parameters=oidc_config.get(
"additional_authorization_parameters", {}
),
passthrough_authorization_parameters=oidc_config.get(
"passthrough_authorization_parameters", []
),
)
@@ -501,3 +504,6 @@ class OidcProviderConfig:
# Additional parameters that will be passed to the authorization grant URL
additional_authorization_parameters: Mapping[str, str]
# Allow query parameters to the redirect endpoint that will be passed to the authorization grant URL
passthrough_authorization_parameters: Collection[str]

View File

@@ -467,6 +467,10 @@ class OidcProvider:
self._sso_handler.register_identity_provider(self)
self.passthrough_authorization_parameters = (
provider.passthrough_authorization_parameters
)
def _validate_metadata(self, m: OpenIDProviderMetadata) -> None:
"""Verifies the provider metadata.
@@ -1005,7 +1009,6 @@ class OidcProvider:
when everything is done (or None for UI Auth)
ui_auth_session_id: The session ID of the ongoing UI Auth (or
None if this is a login).
Returns:
The redirect URL to the authorization endpoint.
@@ -1078,6 +1081,13 @@ class OidcProvider:
)
)
# add passthrough additional authorization parameters
passthrough_authorization_parameters = self.passthrough_authorization_parameters
for parameter in passthrough_authorization_parameters:
parameter_value = parse_string(request, parameter)
if parameter_value:
additional_authorization_parameters.update({parameter: parameter_value})
authorization_endpoint = metadata.get("authorization_endpoint")
return prepare_grant_uri(
authorization_endpoint,

View File

@@ -484,6 +484,32 @@ class OidcHandlerTestCase(HomeserverTestCase):
self.assertEqual(code_verifier, "")
self.assertEqual(redirect, "http://client/redirect")
@override_config(
{
"oidc_config": {
**DEFAULT_CONFIG,
"passthrough_authorization_parameters": ["additional_parameter"],
}
}
)
def test_passthrough_parameters(self) -> None:
"""The redirect request has additional parameters, one is authorized, one is not"""
req = Mock(spec=["cookies", "args"])
req.cookies = []
req.args = {}
req.args[b"additional_parameter"] = ["a_value".encode("utf-8")]
req.args[b"not_authorized_parameter"] = ["any".encode("utf-8")]
url = urlparse(
self.get_success(
self.provider.handle_redirect_request(req, b"http://client/redirect")
)
)
params = parse_qs(url.query)
self.assertEqual(params["additional_parameter"], ["a_value"])
self.assertNotIn("not_authorized_parameters", params)
@override_config({"oidc_config": DEFAULT_CONFIG})
def test_redirect_request_with_code_challenge(self) -> None:
"""The redirect request has the right arguments & generates a valid session cookie."""