From 0c52ec4142fc02e752977278298dc64e95d18ee1 Mon Sep 17 00:00:00 2001 From: gregriff <78878994+gregriff@users.noreply.github.com> Date: Sat, 26 Oct 2024 03:00:08 -0400 Subject: [PATCH] fix: Add optional Nonce parameter to the authorization URL requests (#606) * feat: add optional nonce parameter to the authorization URL requests * fix: shorten docstring to be below max line length --------- Co-authored-by: Greg Griffin --- src/keycloak/keycloak_openid.py | 10 ++++++++-- src/keycloak/urls_patterns.py | 2 +- tests/test_keycloak_openid.py | 4 ++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/keycloak/keycloak_openid.py b/src/keycloak/keycloak_openid.py index 1d32e558..ae9cd82d 100644 --- a/src/keycloak/keycloak_openid.py +++ b/src/keycloak/keycloak_openid.py @@ -257,7 +257,7 @@ def well_known(self): data_raw = self.connection.raw_get(URL_WELL_KNOWN.format(**params_path)) return raise_error_from_response(data_raw, KeycloakGetError) - def auth_url(self, redirect_uri, scope="email", state=""): + def auth_url(self, redirect_uri, scope="email", state="", nonce=""): """Get authorization URL endpoint. :param redirect_uri: Redirect url to receive oauth code @@ -266,6 +266,8 @@ def auth_url(self, redirect_uri, scope="email", state=""): :type scope: str :param state: State will be returned to the redirect_uri :type state: str + :param nonce: Associates a Client session with an ID Token to mitigate replay attacks + :type nonce: str :returns: Authorization URL Full Build :rtype: str """ @@ -275,6 +277,7 @@ def auth_url(self, redirect_uri, scope="email", state=""): "redirect-uri": redirect_uri, "scope": scope, "state": state, + "nonce": nonce, } return URL_AUTH.format(**params_path) @@ -903,7 +906,7 @@ async def a_well_known(self): data_raw = await self.connection.a_raw_get(URL_WELL_KNOWN.format(**params_path)) return raise_error_from_response(data_raw, KeycloakGetError) - async def a_auth_url(self, redirect_uri, scope="email", state=""): + async def a_auth_url(self, redirect_uri, scope="email", state="", nonce=""): """Get authorization URL endpoint asynchronously. :param redirect_uri: Redirect url to receive oauth code @@ -912,6 +915,8 @@ async def a_auth_url(self, redirect_uri, scope="email", state=""): :type scope: str :param state: State will be returned to the redirect_uri :type state: str + :param nonce: Associates a Client session with an ID Token to mitigate replay attacks + :type nonce: str :returns: Authorization URL Full Build :rtype: str """ @@ -921,6 +926,7 @@ async def a_auth_url(self, redirect_uri, scope="email", state=""): "redirect-uri": redirect_uri, "scope": scope, "state": state, + "nonce": nonce, } return URL_AUTH.format(**params_path) diff --git a/src/keycloak/urls_patterns.py b/src/keycloak/urls_patterns.py index a183183a..61e3237f 100644 --- a/src/keycloak/urls_patterns.py +++ b/src/keycloak/urls_patterns.py @@ -35,7 +35,7 @@ URL_ENTITLEMENT = "realms/{realm-name}/authz/entitlement/{resource-server-id}" URL_AUTH = ( "{authorization-endpoint}?client_id={client-id}&response_type=code&redirect_uri={redirect-uri}" - "&scope={scope}&state={state}" + "&scope={scope}&state={state}&nonce={nonce}" ) URL_DEVICE = "realms/{realm-name}/protocol/openid-connect/auth/device" diff --git a/tests/test_keycloak_openid.py b/tests/test_keycloak_openid.py index 20b15994..f26c9b89 100644 --- a/tests/test_keycloak_openid.py +++ b/tests/test_keycloak_openid.py @@ -121,7 +121,7 @@ def test_auth_url(env, oid: KeycloakOpenID): res == f"http://{env.KEYCLOAK_HOST}:{env.KEYCLOAK_PORT}/realms/{oid.realm_name}" + f"/protocol/openid-connect/auth?client_id={oid.client_id}&response_type=code" - + "&redirect_uri=http://test.test/*&scope=email&state=" + + "&redirect_uri=http://test.test/*&scope=email&state=&nonce=" ) @@ -575,7 +575,7 @@ async def test_a_auth_url(env, oid: KeycloakOpenID): res == f"http://{env.KEYCLOAK_HOST}:{env.KEYCLOAK_PORT}/realms/{oid.realm_name}" + f"/protocol/openid-connect/auth?client_id={oid.client_id}&response_type=code" - + "&redirect_uri=http://test.test/*&scope=email&state=" + + "&redirect_uri=http://test.test/*&scope=email&state=&nonce=" )