Skip to content

Commit c8ef007

Browse files
committed
Intial commit for adding support for other authentication strategies
1 parent 295ecf7 commit c8ef007

14 files changed

+456
-347
lines changed
Lines changed: 47 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,77 @@
11
from abc import ABC, abstractmethod
2+
from datetime import datetime, timezone
3+
from typing import Dict
4+
5+
from zitadel_client.auth.open_id import OpenId
26

37

48
class Authenticator(ABC):
59
"""
6-
Abstract base class for authentication strategies.
7-
8-
This class defines a common interface for implementing various
9-
authentication mechanisms. Subclasses must implement the
10-
`get_auth_headers` method to provide the necessary HTTP headers for
11-
authenticated API requests, as well as the `refresh_token` method for
12-
refreshing authentication tokens when needed.
10+
Abstract base class for authenticators.
1311
14-
Attributes:
15-
host (str): The base URL for authentication endpoints.
12+
This class defines the basic structure for any authenticator by requiring the implementation
13+
of a method to retrieve authentication headers, and provides a way to store and retrieve the host.
1614
"""
1715

1816
def __init__(self, host: str):
1917
"""
20-
Initialize the Authenticator with a host URL.
18+
Initializes the Authenticator with the specified host.
2119
22-
Args:
23-
host (str): The base URL for all authentication endpoints.
20+
:param host: The base URL or endpoint for the service.
2421
"""
2522
self.host = host
2623

2724
@abstractmethod
28-
def get_auth_headers(self) -> dict[str, str]:
25+
def get_auth_headers(self) -> Dict[str, str]:
2926
"""
30-
Generate and return the authentication headers required for API requests.
27+
Retrieves the authentication headers to be sent with requests.
3128
32-
Subclasses must implement this method to return a dictionary where the keys
33-
are the header names and the values are the corresponding header values.
29+
Subclasses must override this method to return the appropriate headers.
3430
35-
Returns:
36-
dict[str, str]: A dictionary containing the authentication header(s).
31+
:return: A dictionary mapping header names to their values.
3732
"""
3833
pass
3934

40-
@abstractmethod
41-
def refresh_token(self) -> None:
35+
def get_host(self) -> str:
36+
"""
37+
Returns the stored host.
38+
39+
:return: The host as a string.
4240
"""
43-
Refresh the authentication token.
41+
return self.host
42+
43+
44+
class Token:
45+
def __init__(self, access_token: str, expires_at: datetime):
46+
self.access_token = access_token
47+
self.expires_at = expires_at
48+
49+
def is_expired(self) -> bool:
50+
return datetime.now(timezone.utc) >= self.expires_at
4451

45-
This abstract method must be implemented by subclasses that require a mechanism
46-
to refresh the authentication token. The implementation should update the token
47-
used by the authenticator.
4852

49-
Returns:
50-
None
53+
class OAuthAuthenticatorBuilder(ABC):
54+
"""
55+
Abstract builder class for constructing OAuth authenticator instances.
56+
57+
This builder provides common configuration options such as the OpenId instance and authentication scopes.
58+
"""
59+
60+
def __init__(self, host: str):
5161
"""
52-
pass
62+
Initializes the OAuthAuthenticatorBuilder with a given host.
5363
54-
def get_host(self) -> str:
64+
:param host: The base URL for the OAuth provider.
5565
"""
56-
Retrieve the base host URL.
66+
self.open_id = OpenId(host)
67+
self.auth_scopes = "openid urn:zitadel:iam:org:project:id:zitadel:aud"
5768

58-
This method returns the host URL that was specified during the instantiation
59-
of the Authenticator. It can be used by concrete classes or external consumers
60-
to build full endpoint URLs.
69+
def scopes(self, auth_scopes: set) -> "OAuthAuthenticatorBuilder":
70+
"""
71+
Sets the authentication scopes for the OAuth authenticator.
6172
62-
Returns:
63-
str: The base URL for authentication endpoints.
73+
:param auth_scopes: A set of scope strings.
74+
:return: The builder instance to allow for method chaining.
6475
"""
65-
return self.host
76+
self.auth_scopes = " ".join(auth_scopes)
77+
return self

zitadel_client/auth/client_credentials.py

Lines changed: 0 additions & 49 deletions
This file was deleted.
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
from typing import override
2+
3+
from authlib.integrations.requests_client import OAuth2Session
4+
5+
from zitadel_client.auth.authenticator import OAuthAuthenticatorBuilder
6+
from zitadel_client.auth.oauth_authenticator import OAuthAuthenticator
7+
from zitadel_client.auth.open_id import OpenId
8+
9+
10+
class ClientCredentialsAuthenticator(OAuthAuthenticator):
11+
"""
12+
OAuth authenticator implementing the client credentials flow.
13+
14+
Uses client_id and client_secret to obtain an access token from the OAuth2 token endpoint.
15+
"""
16+
17+
def __init__(self, open_id: OpenId, client_id: str, client_secret: str, auth_scopes: str):
18+
"""
19+
Constructs a ClientCredentialsAuthenticator.
20+
21+
:param open_id: The base URL for the OAuth provider.
22+
:param client_id: The OAuth client identifier.
23+
:param client_secret: The OAuth client secret.
24+
:param auth_scopes: The scope(s) for the token request.
25+
"""
26+
super().__init__(open_id, OAuth2Session(client_id=client_id, client_secret=client_secret, scope=auth_scopes))
27+
28+
@override
29+
def get_grant(self) -> dict:
30+
"""
31+
Returns the grant parameters for the client credentials flow.
32+
33+
:return: A dictionary with the grant type for client credentials.
34+
"""
35+
return {"grant_type": "client_credentials"}
36+
37+
@staticmethod
38+
def builder(host: str, client_id: str, client_secret: str) -> "ClientCredentialsAuthenticatorBuilder":
39+
"""
40+
Returns a builder for constructing a ClientCredentialsAuthenticator.
41+
42+
:param host: The base URL for the OAuth provider.
43+
:param client_id: The OAuth client identifier.
44+
:param client_secret: The OAuth client secret.
45+
:return: A ClientCredentialsAuthenticatorBuilder instance.
46+
"""
47+
return ClientCredentialsAuthenticatorBuilder(host, client_id, client_secret)
48+
49+
50+
class ClientCredentialsAuthenticatorBuilder(OAuthAuthenticatorBuilder):
51+
"""
52+
Builder class for constructing ClientCredentialsAuthenticator instances.
53+
54+
This builder extends the OAuthAuthenticatorBuilder with client credentials (client_id and client_secret)
55+
required for the client credentials flow.
56+
"""
57+
58+
def __init__(self, host: str, client_id: str, client_secret: str):
59+
"""
60+
Initializes the ClientCredentialsAuthenticatorBuilder with host, client ID, and client secret.
61+
62+
:param host: The base URL for the OAuth provider.
63+
:param client_id: The OAuth client identifier.
64+
:param client_secret: The OAuth client secret.
65+
"""
66+
super().__init__(host)
67+
self.client_id = client_id
68+
self.client_secret = client_secret
69+
70+
def build(self) -> ClientCredentialsAuthenticator:
71+
"""
72+
Constructs and returns a ClientCredentialsAuthenticator instance using the configured parameters.
73+
74+
:return: A configured ClientCredentialsAuthenticator.
75+
"""
76+
return ClientCredentialsAuthenticator(
77+
self.open_id, # OpenId instance with endpoint info (constructed from host)
78+
self.client_id, # OAuth client identifier
79+
self.client_secret, # OAuth client secret
80+
self.auth_scopes # Authentication scopes configured in the builder
81+
)

zitadel_client/auth/jwt_auth.py

Lines changed: 0 additions & 121 deletions
This file was deleted.

0 commit comments

Comments
 (0)