From 9ac08ad290baa88202ebc90cf2db78586ca789ed Mon Sep 17 00:00:00 2001 From: TTalex Date: Thu, 30 Apr 2026 12:24:56 +0200 Subject: [PATCH] feat(Auth): Added support for keycloak access_token --- src/openfoodfacts/api.py | 8 ++++++++ src/openfoodfacts/types.py | 10 +++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/openfoodfacts/api.py b/src/openfoodfacts/api.py index be5ee07d..008d6fe3 100644 --- a/src/openfoodfacts/api.py +++ b/src/openfoodfacts/api.py @@ -58,6 +58,10 @@ def _send_request( request_args["cookies"] = request_args.get("cookies", dict()) | { "session": api_config.session_cookie, } + elif api_config.access_token: + request_args["headers"] = request_args.get("headers", dict()) | { + "Authorization": f"Bearer {api_config.access_token}", + } if "auth" not in request_args: request_args["auth"] = get_http_auth(api_config.environment) @@ -595,6 +599,7 @@ def __init__( environment: Union[Environment, str] = Environment.org, session_cookie: Optional[str] = None, timeout: int = 10, + access_token: Optional[str] = None, ) -> None: """Initialize the API instance. @@ -615,6 +620,8 @@ def __init__( :param session_cookie: a session cookie, only used for write requests, defaults to None :param timeout: the timeout for HTTP requests, defaults to 10 seconds + :param access_token: a keycloak access token, generated with single sign on, + only used for write requests, defaults to None """ if not isinstance(country, Country): country = Country[country] @@ -632,6 +639,7 @@ def __init__( password=password, session_cookie=session_cookie, timeout=timeout, + access_token=access_token, ) self.password = password self.country = country diff --git a/src/openfoodfacts/types.py b/src/openfoodfacts/types.py index 3d01522a..018c9e6a 100644 --- a/src/openfoodfacts/types.py +++ b/src/openfoodfacts/types.py @@ -861,6 +861,7 @@ class APIConfig(BaseModel): password: Optional[str] = None session_cookie: Optional[str] = None timeout: float = 10.0 + access_token: Optional[str] = None @model_validator(mode="after") def check_credentials(self): @@ -875,7 +876,14 @@ def check_credentials(self): raise ValueError( "username/password and session_cookie are mutually exclusive" ) - + if self.username and self.access_token: + raise ValueError( + "username/password and access_token are mutually exclusive" + ) + if self.session_cookie and self.access_token: + raise ValueError( + "session_cookie and access_token are mutually exclusive" + ) return self @model_validator(mode="after")