auth0-server-python 1.0.0b1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
auth_types/__init__.py ADDED
@@ -0,0 +1,222 @@
1
+ """
2
+ Type definitions for auth0-server-python SDK.
3
+ These Pydantic models provide type safety and validation for all SDK data structures.
4
+ """
5
+
6
+ from typing import Dict, List, Optional, Any, Union
7
+ from pydantic import BaseModel, Field
8
+ from datetime import datetime
9
+
10
+
11
+ class UserClaims(BaseModel):
12
+ """
13
+ User profile information as returned by Auth0.
14
+ Contains standard OIDC claims about the authenticated user.
15
+ """
16
+ sub: str
17
+ name: Optional[str] = None
18
+ nickname: Optional[str] = None
19
+ given_name: Optional[str] = None
20
+ family_name: Optional[str] = None
21
+ picture: Optional[str] = None
22
+ email: Optional[str] = None
23
+ email_verified: Optional[bool] = None
24
+ org_id: Optional[str] = None
25
+
26
+ class Config:
27
+ extra = "allow" # Allow additional fields not defined in the model
28
+
29
+
30
+ class TokenSet(BaseModel):
31
+ """
32
+ Represents a set of tokens issued by Auth0.
33
+ Contains the access token and related metadata.
34
+ """
35
+ audience: str
36
+ access_token: str
37
+ scope: Optional[str] = None
38
+ expires_at: int
39
+
40
+
41
+ class ConnectionTokenSet(TokenSet):
42
+ """
43
+ Token set specific to a connection.
44
+ Extends TokenSet with connection-specific information.
45
+ """
46
+ connection: str
47
+ login_hint: str
48
+
49
+
50
+ class InternalStateData(BaseModel):
51
+ """
52
+ Internal data used for managing state.
53
+ Not meant to be accessed directly by SDK users.
54
+ """
55
+ sid: str
56
+ created_at: int
57
+
58
+
59
+ class SessionData(BaseModel):
60
+ """
61
+ Represents a user session with Auth0.
62
+ Contains user information and tokens.
63
+ """
64
+ user: Optional[UserClaims] = None
65
+ id_token: Optional[str] = None
66
+ refresh_token: Optional[str] = None
67
+ token_sets: List[TokenSet] = Field(default_factory=list)
68
+ connection_token_sets: List[ConnectionTokenSet] = Field(default_factory=list)
69
+
70
+ class Config:
71
+ extra = "allow" # Allow additional fields not defined in the model
72
+
73
+
74
+ class StateData(SessionData):
75
+ """
76
+ Complete state data stored in the state store.
77
+ Extends SessionData with internal management information.
78
+ """
79
+ internal: InternalStateData
80
+
81
+
82
+ class TransactionData(BaseModel):
83
+ """
84
+ Represents data for an in-progress authentication transaction.
85
+ Used during the authorization code flow to correlate requests.
86
+ """
87
+ audience: Optional[str] = None
88
+ code_verifier: str
89
+ app_state: Optional[Any] = None
90
+
91
+ class Config:
92
+ extra = "allow" # Allow additional fields not defined in the model
93
+
94
+
95
+ class LogoutTokenClaims(BaseModel):
96
+ """
97
+ Claims expected in a logout token.
98
+ Used for backchannel logout processing.
99
+ """
100
+ sub: str
101
+ sid: str
102
+
103
+
104
+ class EncryptedStoreOptions(BaseModel):
105
+ """
106
+ Options for encrypted stores.
107
+ Contains the secret used for encryption.
108
+ """
109
+ secret: str
110
+
111
+
112
+ class ServerClientOptionsBase(BaseModel):
113
+ """
114
+ Base options for configuring the Auth0 server client.
115
+ Contains core settings required for all clients.
116
+ """
117
+ domain: str
118
+ client_id: str
119
+ client_secret: str
120
+ client_assertion_signing_key: Optional[str] = None
121
+ client_assertion_signing_alg: Optional[str] = None
122
+ authorization_params: Optional[Dict[str, Any]] = Field(default_factory=dict)
123
+ transaction_identifier: Optional[str] = "_a0_tx"
124
+ state_identifier: Optional[str] = "_a0_session"
125
+ custom_fetch: Optional[Any] = None # Function type hint would be more complex
126
+
127
+
128
+ class ServerClientOptionsWithSecret(ServerClientOptionsBase):
129
+ """
130
+ Client options using a secret for encryption.
131
+ Extends base options with secret and duration settings.
132
+ """
133
+ secret: str
134
+ state_absolute_duration: Optional[int] = 259200 # 3 days in seconds
135
+
136
+
137
+ class StartInteractiveLoginOptions(BaseModel):
138
+ """
139
+ Options for starting the interactive login process.
140
+ Configures how the authorization request is constructed.
141
+ """
142
+ pushed_authorization_requests: Optional[bool] = False
143
+ app_state: Optional[Any] = None
144
+ authorization_params: Optional[Dict[str, Any]] = None
145
+
146
+
147
+ class LoginBackchannelOptions(BaseModel):
148
+ """
149
+ Options for backchannel authentication.
150
+ Configures how the backchannel authentication request is constructed.
151
+ """
152
+ binding_message: Optional[str] = None
153
+ login_hint: Optional[Dict[str, str]] = None
154
+ authorization_params: Optional[Dict[str, Any]] = None
155
+
156
+
157
+ class LogoutOptions(BaseModel):
158
+ """
159
+ Options for logout operations.
160
+ Configures how the logout request is constructed.
161
+ """
162
+ return_to: Optional[str] = None
163
+
164
+
165
+ class AuthorizationParameters(BaseModel):
166
+ """
167
+ Parameters used in authorization requests.
168
+ Based on standard OAuth2/OIDC parameters.
169
+ """
170
+ scope: Optional[str] = None
171
+ audience: Optional[str] = None
172
+ redirect_uri: Optional[str] = None
173
+
174
+ class Config:
175
+ extra = "allow" # Allow additional OAuth parameters
176
+
177
+ class AuthorizationDetails(BaseModel):
178
+ """
179
+ Authorization details returned from Auth0.
180
+ Used for Resource Access Rights (RAR).
181
+ """
182
+ type: str
183
+ actions: Optional[List[str]] = None
184
+ locations: Optional[List[str]] = None
185
+ datatypes: Optional[List[str]] = None
186
+ identifier: Optional[str] = None
187
+
188
+ class Config:
189
+ extra = "allow" # Allow additional fields not defined in the model
190
+
191
+
192
+ class LoginBackchannelOptions(BaseModel):
193
+ """
194
+ Options for Client-Initiated Backchannel Authentication.
195
+ """
196
+ binding_message: str
197
+ login_hint: Dict[str, str] # Should contain a 'sub' field
198
+ authorization_params: Optional[Dict[str, Any]] = None
199
+
200
+ class Config:
201
+ extra = "allow" # Allow additional fields not defined in the model
202
+
203
+
204
+ class LoginBackchannelResult(BaseModel):
205
+ """
206
+ Result from Client-Initiated Backchannel Authentication.
207
+ """
208
+ authorization_details: Optional[List[AuthorizationDetails]] = None
209
+
210
+
211
+ class AccessTokenForConnectionOptions(BaseModel):
212
+ """
213
+ Options for retrieving an access token for a specific connection.
214
+ """
215
+ connection: str
216
+ login_hint: Optional[str] = None
217
+
218
+ class StartLinkUserOptions(BaseModel):
219
+ connection: str
220
+ connection_scope: Optional[str] = None
221
+ authorization_params: Optional[Dict[str, Any]] = None
222
+ app_state: Optional[Any] = None
encryption/__init__.py ADDED
@@ -0,0 +1,4 @@
1
+ from .encrypt import encrypt, decrypt
2
+
3
+
4
+ _all__=["encrypt", "decrypt"]
encryption/encrypt.py ADDED
@@ -0,0 +1,73 @@
1
+ from __future__ import annotations
2
+ from typing import Any
3
+
4
+ import json
5
+ from cryptography.hazmat.primitives.kdf.hkdf import HKDF
6
+ from cryptography.hazmat.primitives import hashes
7
+ from jwcrypto import jwk, jwe
8
+ from jwcrypto.common import base64url_encode
9
+
10
+ # Constants equivalent to the TypeScript version
11
+ ENC = 'A256CBC-HS512'
12
+ ALG = 'dir'
13
+ DIGEST = hashes.SHA256()
14
+ BYTE_LENGTH = 64
15
+ ENCRYPTION_INFO = b'Auth0 Generated ryption'
16
+
17
+
18
+
19
+ def derive_encryption_key(secret: bytes, salt: bytes) -> bytes:
20
+ """
21
+ Derives a key using HKDF with SHA-256.
22
+ """
23
+ hkdf = HKDF(
24
+ algorithm=DIGEST,
25
+ length=BYTE_LENGTH,
26
+ salt=salt,
27
+ info=ENCRYPTION_INFO,
28
+ )
29
+ return hkdf.derive(secret)
30
+
31
+ def encrypt(payload: dict, secret: str, salt: str) -> str:
32
+ """
33
+ Encrypts the given payload into a JWE using the direct algorithm and A256CBC-HS512 encryption.
34
+ """
35
+ # Convert secret and salt to bytes
36
+ secret_bytes = secret.encode('utf-8')
37
+ salt_bytes = salt.encode('utf-8')
38
+
39
+ # Derive the encryption key
40
+ encryption_secret = derive_encryption_key(secret_bytes, salt_bytes)
41
+
42
+ # Create a symmetric key for JWE. jwcrypto expects the key as a base64url-encoded string.
43
+ key = jwk.JWK(k=base64url_encode(encryption_secret), kty="oct")
44
+
45
+ payload_json = json.dumps(payload)
46
+
47
+ # Create a JWE object with the specified header
48
+ jwetoken = jwe.JWE(
49
+ payload_json,
50
+ protected={'alg': ALG, 'enc': ENC}
51
+ )
52
+
53
+ jwetoken.add_recipient(key)
54
+ c = jwetoken.serialize(compact=True)
55
+
56
+ # Return the compact serialization of the token
57
+ return jwetoken.serialize(compact=True)
58
+
59
+ def decrypt(token: str, secret: str, salt: str) -> dict:
60
+ """
61
+ Decrypts the JWE token back to the original payload.
62
+ """
63
+ secret_bytes = secret.encode('utf-8')
64
+ salt_bytes = salt.encode('utf-8')
65
+
66
+ encryption_secret = derive_encryption_key(secret_bytes, salt_bytes)
67
+ key = jwk.JWK(k=base64url_encode(encryption_secret), kty="oct")
68
+
69
+ jwetoken = jwe.JWE()
70
+ jwetoken.deserialize(token)
71
+ jwetoken.decrypt(key)
72
+ payload_json = jwetoken.payload.decode('utf-8')
73
+ return json.loads(payload_json)
error/__init__.py ADDED
@@ -0,0 +1,119 @@
1
+ """
2
+ Error classes for the auth0-server-python SDK.
3
+ These exceptions provide specific error types for different failure scenarios.
4
+ """
5
+
6
+ class Auth0Error(Exception):
7
+ """Base class for all Auth0 SDK errors."""
8
+
9
+ def __init__(self, message=None):
10
+ self.message = message
11
+ super().__init__(message)
12
+
13
+
14
+ class MissingTransactionError(Auth0Error):
15
+ """
16
+ Error raised when a required transaction is missing.
17
+ This typically happens during the callback phase when the transaction
18
+ from the initial authorization request cannot be found.
19
+ """
20
+ code = "missing_transaction_error"
21
+
22
+ def __init__(self, message=None):
23
+ super().__init__(message or "The transaction is missing.")
24
+ self.name = "MissingTransactionError"
25
+
26
+
27
+ class ApiError(Auth0Error):
28
+ """
29
+ Error raised when an API request to Auth0 fails.
30
+ Contains details about the original error from Auth0.
31
+ """
32
+
33
+ def __init__(self, code: str, message: str, cause=None):
34
+ super().__init__(message)
35
+ self.code = code
36
+ self.cause = cause
37
+
38
+ # Extract additional error details if available
39
+ if cause:
40
+ self.error = getattr(cause, "error", None)
41
+ self.error_description = getattr(cause, "error_description", None)
42
+ else:
43
+ self.error = None
44
+ self.error_description = None
45
+
46
+
47
+ class AccessTokenError(Auth0Error):
48
+ """Error raised when there's an issue with access tokens."""
49
+
50
+ def __init__(self, code: str, message: str):
51
+ super().__init__(message)
52
+ self.code = code
53
+ self.name = "AccessTokenError"
54
+
55
+
56
+ class MissingRequiredArgumentError(Auth0Error):
57
+ """
58
+ Error raised when a required argument is missing.
59
+ Includes the name of the missing argument in the error message.
60
+ """
61
+ code = "missing_required_argument_error"
62
+
63
+ def __init__(self, argument: str):
64
+ message = f"The argument '{argument}' is required but was not provided."
65
+ super().__init__(message)
66
+ self.name = "MissingRequiredArgumentError"
67
+ self.argument = argument
68
+
69
+
70
+ class BackchannelLogoutError(Auth0Error):
71
+ """
72
+ Error raised during backchannel logout processing.
73
+ This can happen when validating or processing logout tokens.
74
+ """
75
+ code = "backchannel_logout_error"
76
+
77
+ def __init__(self, message: str):
78
+ super().__init__(message)
79
+ self.name = "BackchannelLogoutError"
80
+
81
+
82
+ class AccessTokenForConnectionError(Auth0Error):
83
+ """Error when retrieving access tokens for a specific connection fails."""
84
+
85
+ def __init__(self, code: str, message: str):
86
+ super().__init__(message)
87
+ self.code = code
88
+ self.name = "AccessTokenForConnectionError"
89
+
90
+ class StartLinkUserError(Auth0Error):
91
+ """
92
+ Error raised when user linking process fails to start.
93
+ This typically happens when trying to link accounts without
94
+ having an authenticated user first.
95
+ """
96
+ code = "start_link_user_error"
97
+
98
+ def __init__(self, message: str):
99
+ super().__init__(message)
100
+ self.name = "StartLinkUserError"
101
+
102
+
103
+ # Error code enumerations - these can be used to identify specific error scenarios
104
+
105
+ class AccessTokenErrorCode:
106
+ """Error codes for access token operations."""
107
+ MISSING_SESSION = "missing_session"
108
+ MISSING_REFRESH_TOKEN = "missing_refresh_token"
109
+ FAILED_TO_REFRESH_TOKEN = "failed_to_refresh_token"
110
+ FAILED_TO_REQUEST_TOKEN = "failed_to_request_token"
111
+ REFRESH_TOKEN_ERROR = "refresh_token_error"
112
+
113
+
114
+ class AccessTokenForConnectionErrorCode:
115
+ """Error codes for connection-specific token operations."""
116
+ MISSING_REFRESH_TOKEN = "missing_refresh_token"
117
+ FAILED_TO_RETRIEVE = "failed_to_retrieve"
118
+ API_ERROR = "api_error"
119
+ FETCH_ERROR = "retrieval_error"
store/__init__.py ADDED
@@ -0,0 +1,7 @@
1
+ from .abstract import AbstractDataStore, StateStore, TransactionStore
2
+
3
+ __all__ = [
4
+ "AbstractDataStore",
5
+ "StateStore",
6
+ "TransactionStore",
7
+ ]
store/abstract.py ADDED
@@ -0,0 +1,113 @@
1
+ from abc import ABC, abstractmethod
2
+ from typing import Generic, TypeVar, Optional, Dict, Any
3
+
4
+ from encryption import encrypt, decrypt
5
+
6
+ T = TypeVar('T') # Generic type for the data stored
7
+
8
+ class AbstractDataStore(Generic[T], ABC):
9
+ """
10
+ Abstract base class for data stores.
11
+ Provides common functionality for different store implementations.
12
+ """
13
+
14
+ def __init__(self, options: Dict[str, Any]):
15
+ """
16
+ Initialize the data store with options.
17
+
18
+ Args:
19
+ options: Configuration options including encryption secret
20
+ """
21
+ self._options = options
22
+
23
+ @abstractmethod
24
+ async def set(self, identifier: str, state: T, remove_if_expires: bool = False, options: Optional[Dict[str, Any]] = None) -> None:
25
+ """
26
+ Store data with the given identifier.
27
+
28
+ Args:
29
+ identifier: Unique key for the stored data
30
+ state: Data to store
31
+ remove_if_expires: Whether to auto-remove expired data
32
+ options: Additional operation-specific options
33
+ """
34
+ pass
35
+
36
+ @abstractmethod
37
+ async def get(self, identifier: str, options: Optional[Dict[str, Any]] = None) -> Optional[T]:
38
+ """
39
+ Retrieve data by identifier.
40
+
41
+ Args:
42
+ identifier: Unique key for the stored data
43
+ options: Additional operation-specific options
44
+
45
+ Returns:
46
+ The stored data or None if not found
47
+ """
48
+ pass
49
+
50
+ @abstractmethod
51
+ async def delete(self, identifier: str, options: Optional[Dict[str, Any]] = None) -> None:
52
+ """
53
+ Delete data by identifier.
54
+
55
+ Args:
56
+ identifier: Unique key for the stored data
57
+ options: Additional operation-specific options
58
+ """
59
+ pass
60
+
61
+ def encrypt(self, identifier: str, state_data: Dict[str, Any]) -> T:
62
+ """
63
+ Encrypt data before storing.
64
+
65
+ Args:
66
+ identifier: Unique key used as part of encryption salt
67
+ state_data: Data to encrypt
68
+
69
+ Returns:
70
+ Encrypted string representation of the data
71
+ """
72
+ return encrypt(state_data, self._options.get("secret"), identifier)
73
+
74
+ def decrypt(self, identifier: str, encrypted_data: str) -> T:
75
+ """
76
+ Decrypt data after retrieval.
77
+
78
+ Args:
79
+ identifier: Unique key used as part of encryption salt
80
+ encrypted_data: Encrypted data to decrypt
81
+
82
+ Returns:
83
+ Decrypted data
84
+ """
85
+ return decrypt(encrypted_data, self._options.get("secret"), identifier)
86
+
87
+
88
+ class StateStore(AbstractDataStore[Dict[str, Any]]):
89
+ """
90
+ Abstract store for persistent session data.
91
+ Extends AbstractDataStore with logout token functionality.
92
+ """
93
+
94
+ async def delete_by_logout_token(self, claims: Dict[str, Any], options: Optional[Dict[str, Any]] = None) -> None:
95
+ """
96
+ Delete sessions based on logout token claims.
97
+
98
+ Args:
99
+ claims: Claims from the logout token
100
+ options: Additional operation-specific options
101
+
102
+ Note:
103
+ Default implementation throws NotImplementedError.
104
+ Concrete implementations should override this method.
105
+ """
106
+ raise NotImplementedError("Method not implemented.")
107
+
108
+
109
+ class TransactionStore(AbstractDataStore[Dict[str, Any]]):
110
+ """
111
+ Abstract store for temporary transaction data during auth flows.
112
+ """
113
+ pass
utils/__init__.py ADDED
@@ -0,0 +1,7 @@
1
+ """
2
+ Utility functions for auth0-server-python SDK.
3
+ These helpers provide common functionality used across the SDK.
4
+ """
5
+ from .helpers import PKCE, State, URL
6
+
7
+ __all__ = ["PKCE", "State", "URL"]