From a9409b8a36eed0e8ce70dab02aa559fad4c86a15 Mon Sep 17 00:00:00 2001 From: Gabriel Rudloff Date: Mon, 22 Sep 2025 07:19:31 +0000 Subject: [PATCH] chore: address linting and formatting issues --- src/keycloak/keycloak_openid.py | 12 ++++++------ src/keycloak/pkce_utils.py | 27 +++++++++++++++++---------- tests/test_pkce_flow.py | 24 ++++++++++++++---------- 3 files changed, 37 insertions(+), 26 deletions(-) diff --git a/src/keycloak/keycloak_openid.py b/src/keycloak/keycloak_openid.py index abedc7c..9f26bfd 100644 --- a/src/keycloak/keycloak_openid.py +++ b/src/keycloak/keycloak_openid.py @@ -282,8 +282,8 @@ class KeycloakOpenID: scope: str = "email", state: str = "", nonce: str = "", - code_challenge: str = None, - code_challenge_method: str = None, + code_challenge: str | None = None, + code_challenge_method: str | None = None, ) -> str: """ Get authorization URL endpoint. @@ -327,7 +327,7 @@ class KeycloakOpenID: redirect_uri: str = "", totp: int | None = None, scope: str = "openid", - code_verifier: str = None, + code_verifier: str | None = None, **extra: dict, ) -> dict: """ @@ -1044,8 +1044,8 @@ class KeycloakOpenID: scope: str = "email", state: str = "", nonce: str = "", - code_challenge: str = None, - code_challenge_method: str = None, + code_challenge: str | None = None, + code_challenge_method: str | None = None, ) -> str: """ Get authorization URL endpoint asynchronously. @@ -1089,7 +1089,7 @@ class KeycloakOpenID: redirect_uri: str = "", totp: int | None = None, scope: str = "openid", - code_verifier: str = None, + code_verifier: str | None = None, **extra: dict, ) -> dict: """ diff --git a/src/keycloak/pkce_utils.py b/src/keycloak/pkce_utils.py index 2953bc6..015bb3f 100644 --- a/src/keycloak/pkce_utils.py +++ b/src/keycloak/pkce_utils.py @@ -19,30 +19,37 @@ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +"""PKCE utility functions for code verifier and code challenge generation.""" + import base64 import hashlib import os -from typing import Tuple def generate_code_verifier(length: int = 128) -> str: """ - Generates a high-entropy cryptographic random string for PKCE code_verifier. + Generate a high-entropy cryptographic random string for PKCE code_verifier. + RFC 7636 recommends a length between 43 and 128 characters. """ return base64.urlsafe_b64encode(os.urandom(length)).rstrip(b"=").decode("utf-8")[:length] -def generate_code_challenge(code_verifier: str, method: str = "S256") -> Tuple[str, str]: + +def generate_code_challenge(code_verifier: str, method: str = "S256") -> tuple[str, str]: """ - Generates a code_challenge from the code_verifier using the specified method. - Supported methods: "S256" (default), "plain" - Returns (code_challenge, code_challenge_method) + Generate a code_challenge from the code_verifier using the specified method. + + Supported methods: "S256" (default), "plain". + Returns (code_challenge, code_challenge_method). """ if method == "S256": - code_challenge = base64.urlsafe_b64encode( - hashlib.sha256(code_verifier.encode("utf-8")).digest() - ).rstrip(b"=").decode("utf-8") + code_challenge = ( + base64.urlsafe_b64encode(hashlib.sha256(code_verifier.encode("utf-8")).digest()) + .rstrip(b"=") + .decode("utf-8") + ) return code_challenge, "S256" if method == "plain": return code_verifier, "plain" - raise ValueError(f"Unsupported PKCE method: {method}") + error_msg = f"Unsupported PKCE method: {method}" + raise ValueError(error_msg) diff --git a/tests/test_pkce_flow.py b/tests/test_pkce_flow.py index 3823f7f..c52b465 100644 --- a/tests/test_pkce_flow.py +++ b/tests/test_pkce_flow.py @@ -1,13 +1,13 @@ +"""Tests for PKCE flow: code verifier and code challenge handling.""" + from unittest import mock from keycloak import KeycloakOpenID from keycloak.pkce_utils import generate_code_challenge, generate_code_verifier -def test_pkce_auth_url_and_token(env): - """ - Test PKCE flow: auth_url includes code_challenge, token includes code_verifier. - """ +def test_pkce_auth_url_and_token(env: object) -> None: + """Test PKCE flow: auth_url includes code_challenge, token includes code_verifier.""" oid = KeycloakOpenID( server_url=f"http://{env.keycloak_host}:{env.keycloak_port}", realm_name="master", @@ -27,11 +27,15 @@ def test_pkce_auth_url_and_token(env): # Simulate token exchange with PKCE # This part would require a real code from Keycloak, so we mock the response - with mock.patch.object(oid, "token", return_value={ - "access_token": mock.ANY, - "refresh_token": mock.ANY, - "token_type": "Bearer", - }) as mocked_token: + with mock.patch.object( + oid, + "token", + return_value={ + "access_token": mock.ANY, + "refresh_token": mock.ANY, + "token_type": "Bearer", + }, + ) as mocked_token: token = oid.token( grant_type="authorization_code", code="dummy_code", @@ -46,4 +50,4 @@ def test_pkce_auth_url_and_token(env): ) assert "access_token" in token assert "refresh_token" in token - assert token["token_type"] == "Bearer" + assert token["token_type"] == "Bearer" # noqa: S105