herfy-auth 1.0.0__tar.gz

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.
@@ -0,0 +1,317 @@
1
+ Metadata-Version: 2.4
2
+ Name: herfy-auth
3
+ Version: 1.0.0
4
+ Summary: Authentication SDK for integrating with Herfy Control Center
5
+ Author: Herfy Development Team
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/herfy/helpdesk
8
+ Project-URL: Documentation, https://github.com/herfy/helpdesk/tree/main/packages/auth-sdk
9
+ Keywords: auth,oauth2,sso,jwt,fastapi
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.9
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Framework :: FastAPI
19
+ Classifier: Topic :: Security
20
+ Requires-Python: >=3.9
21
+ Description-Content-Type: text/markdown
22
+ Requires-Dist: httpx>=0.24.0
23
+ Requires-Dist: python-jose[cryptography]>=3.3.0
24
+ Requires-Dist: pydantic>=2.0.0
25
+ Provides-Extra: fastapi
26
+ Requires-Dist: fastapi>=0.100.0; extra == "fastapi"
27
+ Requires-Dist: starlette>=0.27.0; extra == "fastapi"
28
+ Provides-Extra: dev
29
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
30
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
31
+ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
32
+ Requires-Dist: black>=23.0.0; extra == "dev"
33
+ Requires-Dist: mypy>=1.0.0; extra == "dev"
34
+
35
+ # Herfy Auth SDK
36
+
37
+ Authentication SDK for integrating applications with the Herfy Control Center.
38
+
39
+ ## Features
40
+
41
+ - **Local JWT Validation**: Validate tokens locally using a shared secret (fast, no network calls)
42
+ - **Remote Token Validation**: Validate tokens via Control Center API (always up-to-date)
43
+ - **OAuth2 Authorization Code Flow**: Redirect users to Control Center for authentication
44
+ - **Client Credentials Flow**: App-to-app authentication
45
+ - **FastAPI Integration**: Ready-to-use dependencies and middleware
46
+ - **Token Caching**: Built-in caching to reduce validation overhead
47
+
48
+ ## Installation
49
+
50
+ ```bash
51
+ # From PyPI (recommended for app repos)
52
+ pip install herfy-auth==1.0.0
53
+
54
+ # With FastAPI support
55
+ pip install "herfy-auth[fastapi]==1.0.0"
56
+
57
+ # Local editable install (monorepo development)
58
+ pip install -e packages/auth-sdk
59
+ ```
60
+
61
+ ### Publishing
62
+
63
+ Create a PyPI API token and add it as a GitHub repository secret:
64
+
65
+ - `PYPI_API_TOKEN`
66
+
67
+ ## Quick Start
68
+
69
+ ### 1. Environment Configuration
70
+
71
+ Set these environment variables:
72
+
73
+ ```bash
74
+ # Required
75
+ CONTROL_CENTER_URL=https://control.herfy.com
76
+ SECRET_KEY=your-shared-jwt-secret # Same as Control Center
77
+
78
+ # For OAuth flows (optional)
79
+ AUTH_CLIENT_ID=your-app-id
80
+ AUTH_CLIENT_SECRET=your-app-secret
81
+
82
+ # Optional settings
83
+ TOKEN_VALIDATION_MODE=local # "local" or "remote"
84
+ TOKEN_CACHE_TTL=300 # seconds
85
+ ```
86
+
87
+ ### 2. FastAPI Integration
88
+
89
+ ```python
90
+ from fastapi import FastAPI, Depends
91
+ from herfy_auth import init_auth, get_current_user, require_auth, UserInfo
92
+
93
+ app = FastAPI()
94
+
95
+ # Initialize auth (call once at startup)
96
+ init_auth(
97
+ public_routes=["/health", "/api/public"],
98
+ public_prefixes=["/static/"],
99
+ )
100
+
101
+ # Protect routes with authentication
102
+ @app.get("/api/profile")
103
+ async def get_profile(user: UserInfo = Depends(get_current_user)):
104
+ return {
105
+ "id": user.id,
106
+ "email": user.email,
107
+ "roles": user.roles,
108
+ }
109
+
110
+ # Require specific roles
111
+ @app.get("/api/admin")
112
+ async def admin_only(user: UserInfo = Depends(require_auth(roles=["admin"]))):
113
+ return {"admin": True}
114
+
115
+ # Require any of multiple roles
116
+ @app.get("/api/staff")
117
+ async def staff_route(
118
+ user: UserInfo = Depends(require_auth(roles=["admin", "agent"], any_role=True))
119
+ ):
120
+ return {"staff": True}
121
+ ```
122
+
123
+ ### 3. OAuth2 Login Flow
124
+
125
+ ```python
126
+ from fastapi import FastAPI, Request
127
+ from fastapi.responses import RedirectResponse
128
+ from herfy_auth import HerfyAuthClient, AuthConfig
129
+
130
+ app = FastAPI()
131
+ auth_client = HerfyAuthClient(
132
+ control_center_url="https://control.herfy.com",
133
+ client_id="your-app-id",
134
+ client_secret="your-app-secret",
135
+ )
136
+
137
+ @app.get("/login")
138
+ async def login():
139
+ # Redirect user to Control Center login
140
+ login_url = auth_client.get_login_url(
141
+ redirect_uri="https://your-app.com/callback",
142
+ state="random-csrf-token",
143
+ )
144
+ return RedirectResponse(login_url)
145
+
146
+ @app.get("/callback")
147
+ async def callback(code: str, state: str):
148
+ # Exchange authorization code for tokens
149
+ tokens = await auth_client.exchange_code(
150
+ code=code,
151
+ redirect_uri="https://your-app.com/callback",
152
+ )
153
+
154
+ # Get user info
155
+ user = await auth_client.validate_token(tokens.access_token)
156
+
157
+ return {
158
+ "access_token": tokens.access_token,
159
+ "user": {
160
+ "id": user.id,
161
+ "email": user.email,
162
+ }
163
+ }
164
+ ```
165
+
166
+ ### 4. App-to-App Authentication
167
+
168
+ ```python
169
+ from herfy_auth import HerfyAuthClient
170
+
171
+ # For backend services that need to call the helpdesk API
172
+ auth_client = HerfyAuthClient(
173
+ control_center_url="https://control.herfy.com",
174
+ client_id="your-service-app-id",
175
+ client_secret="your-service-app-secret",
176
+ )
177
+
178
+ # Get a token for API calls
179
+ async def call_helpdesk_api():
180
+ tokens = await auth_client.get_client_credentials_token()
181
+
182
+ # Use the token to call other APIs
183
+ async with httpx.AsyncClient() as client:
184
+ response = await client.get(
185
+ "https://helpdesk-api.herfy.com/api/tickets",
186
+ headers={"Authorization": f"Bearer {tokens.access_token}"}
187
+ )
188
+ return response.json()
189
+ ```
190
+
191
+ ## API Reference
192
+
193
+ ### HerfyAuthClient
194
+
195
+ Main client class for authentication operations.
196
+
197
+ ```python
198
+ client = HerfyAuthClient(
199
+ control_center_url="https://control.herfy.com",
200
+ client_id="app-id", # Optional: for OAuth flows
201
+ client_secret="app-secret", # Optional: for OAuth flows
202
+ jwt_secret="shared-secret", # Optional: for local validation
203
+ )
204
+
205
+ # Validate a token
206
+ user = await client.validate_token(token)
207
+
208
+ # Get OAuth login URL
209
+ url = client.get_login_url(redirect_uri, state)
210
+
211
+ # Exchange authorization code
212
+ tokens = await client.exchange_code(code, redirect_uri)
213
+
214
+ # Get client credentials token
215
+ tokens = await client.get_client_credentials_token()
216
+
217
+ # Refresh a token
218
+ tokens = await client.refresh_token(refresh_token)
219
+ ```
220
+
221
+ ### UserInfo
222
+
223
+ User information model returned from token validation.
224
+
225
+ ```python
226
+ user = await client.validate_token(token)
227
+
228
+ user.id # User ID
229
+ user.email # Email address
230
+ user.roles # List of roles
231
+ user.org_roles # Organization roles
232
+ user.permissions # List of permissions
233
+ user.is_admin() # Check if admin
234
+ user.has_role("agent") # Check specific role
235
+ user.has_permission("tickets:read") # Check permission
236
+ ```
237
+
238
+ ### FastAPI Dependencies
239
+
240
+ ```python
241
+ from herfy_auth import get_current_user, get_optional_user, require_auth, require_admin
242
+
243
+ # Basic auth required
244
+ user = Depends(get_current_user)
245
+
246
+ # Optional auth (returns None if not authenticated)
247
+ user = Depends(get_optional_user)
248
+
249
+ # Require specific roles
250
+ user = Depends(require_auth(roles=["admin"]))
251
+
252
+ # Require any of multiple roles
253
+ user = Depends(require_auth(roles=["admin", "manager"], any_role=True))
254
+
255
+ # Require specific permissions
256
+ user = Depends(require_auth(permissions=["tickets:write"]))
257
+
258
+ # Convenience admin check
259
+ user = Depends(require_admin())
260
+ ```
261
+
262
+ ## Configuration
263
+
264
+ ### AuthConfig
265
+
266
+ ```python
267
+ from herfy_auth import AuthConfig
268
+
269
+ config = AuthConfig(
270
+ control_center_url="https://control.herfy.com",
271
+ client_id="app-id",
272
+ client_secret="app-secret",
273
+ jwt_secret="shared-secret",
274
+ jwt_algorithm="HS256",
275
+ token_validation_mode="local", # "local" or "remote"
276
+ cache_ttl_seconds=300,
277
+ )
278
+
279
+ # Or load from environment
280
+ config = AuthConfig.from_env()
281
+ ```
282
+
283
+ ### Environment Variables
284
+
285
+ | Variable | Description | Default |
286
+ |----------|-------------|---------|
287
+ | `CONTROL_CENTER_URL` | Control Center API URL | `http://localhost:8001` |
288
+ | `AUTH_CLIENT_ID` | OAuth client ID | - |
289
+ | `AUTH_CLIENT_SECRET` | OAuth client secret | - |
290
+ | `SECRET_KEY` / `JWT_SECRET` | JWT signing secret | - |
291
+ | `JWT_ALGORITHM` | JWT algorithm | `HS256` |
292
+ | `TOKEN_VALIDATION_MODE` | `local` or `remote` | `local` |
293
+ | `TOKEN_CACHE_TTL` | Cache TTL in seconds | `300` |
294
+
295
+ ## Token Validation Modes
296
+
297
+ ### Local Validation (Recommended)
298
+
299
+ Validates JWT tokens locally using a shared secret. Fast and doesn't require network calls.
300
+
301
+ ```bash
302
+ TOKEN_VALIDATION_MODE=local
303
+ SECRET_KEY=same-key-as-control-center
304
+ ```
305
+
306
+ ### Remote Validation
307
+
308
+ Validates tokens by calling the Control Center's `/oauth/userinfo` endpoint. Always up-to-date but requires network calls.
309
+
310
+ ```bash
311
+ TOKEN_VALIDATION_MODE=remote
312
+ CONTROL_CENTER_URL=https://control.herfy.com
313
+ ```
314
+
315
+ ## License
316
+
317
+ MIT
@@ -0,0 +1,283 @@
1
+ # Herfy Auth SDK
2
+
3
+ Authentication SDK for integrating applications with the Herfy Control Center.
4
+
5
+ ## Features
6
+
7
+ - **Local JWT Validation**: Validate tokens locally using a shared secret (fast, no network calls)
8
+ - **Remote Token Validation**: Validate tokens via Control Center API (always up-to-date)
9
+ - **OAuth2 Authorization Code Flow**: Redirect users to Control Center for authentication
10
+ - **Client Credentials Flow**: App-to-app authentication
11
+ - **FastAPI Integration**: Ready-to-use dependencies and middleware
12
+ - **Token Caching**: Built-in caching to reduce validation overhead
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ # From PyPI (recommended for app repos)
18
+ pip install herfy-auth==1.0.0
19
+
20
+ # With FastAPI support
21
+ pip install "herfy-auth[fastapi]==1.0.0"
22
+
23
+ # Local editable install (monorepo development)
24
+ pip install -e packages/auth-sdk
25
+ ```
26
+
27
+ ### Publishing
28
+
29
+ Create a PyPI API token and add it as a GitHub repository secret:
30
+
31
+ - `PYPI_API_TOKEN`
32
+
33
+ ## Quick Start
34
+
35
+ ### 1. Environment Configuration
36
+
37
+ Set these environment variables:
38
+
39
+ ```bash
40
+ # Required
41
+ CONTROL_CENTER_URL=https://control.herfy.com
42
+ SECRET_KEY=your-shared-jwt-secret # Same as Control Center
43
+
44
+ # For OAuth flows (optional)
45
+ AUTH_CLIENT_ID=your-app-id
46
+ AUTH_CLIENT_SECRET=your-app-secret
47
+
48
+ # Optional settings
49
+ TOKEN_VALIDATION_MODE=local # "local" or "remote"
50
+ TOKEN_CACHE_TTL=300 # seconds
51
+ ```
52
+
53
+ ### 2. FastAPI Integration
54
+
55
+ ```python
56
+ from fastapi import FastAPI, Depends
57
+ from herfy_auth import init_auth, get_current_user, require_auth, UserInfo
58
+
59
+ app = FastAPI()
60
+
61
+ # Initialize auth (call once at startup)
62
+ init_auth(
63
+ public_routes=["/health", "/api/public"],
64
+ public_prefixes=["/static/"],
65
+ )
66
+
67
+ # Protect routes with authentication
68
+ @app.get("/api/profile")
69
+ async def get_profile(user: UserInfo = Depends(get_current_user)):
70
+ return {
71
+ "id": user.id,
72
+ "email": user.email,
73
+ "roles": user.roles,
74
+ }
75
+
76
+ # Require specific roles
77
+ @app.get("/api/admin")
78
+ async def admin_only(user: UserInfo = Depends(require_auth(roles=["admin"]))):
79
+ return {"admin": True}
80
+
81
+ # Require any of multiple roles
82
+ @app.get("/api/staff")
83
+ async def staff_route(
84
+ user: UserInfo = Depends(require_auth(roles=["admin", "agent"], any_role=True))
85
+ ):
86
+ return {"staff": True}
87
+ ```
88
+
89
+ ### 3. OAuth2 Login Flow
90
+
91
+ ```python
92
+ from fastapi import FastAPI, Request
93
+ from fastapi.responses import RedirectResponse
94
+ from herfy_auth import HerfyAuthClient, AuthConfig
95
+
96
+ app = FastAPI()
97
+ auth_client = HerfyAuthClient(
98
+ control_center_url="https://control.herfy.com",
99
+ client_id="your-app-id",
100
+ client_secret="your-app-secret",
101
+ )
102
+
103
+ @app.get("/login")
104
+ async def login():
105
+ # Redirect user to Control Center login
106
+ login_url = auth_client.get_login_url(
107
+ redirect_uri="https://your-app.com/callback",
108
+ state="random-csrf-token",
109
+ )
110
+ return RedirectResponse(login_url)
111
+
112
+ @app.get("/callback")
113
+ async def callback(code: str, state: str):
114
+ # Exchange authorization code for tokens
115
+ tokens = await auth_client.exchange_code(
116
+ code=code,
117
+ redirect_uri="https://your-app.com/callback",
118
+ )
119
+
120
+ # Get user info
121
+ user = await auth_client.validate_token(tokens.access_token)
122
+
123
+ return {
124
+ "access_token": tokens.access_token,
125
+ "user": {
126
+ "id": user.id,
127
+ "email": user.email,
128
+ }
129
+ }
130
+ ```
131
+
132
+ ### 4. App-to-App Authentication
133
+
134
+ ```python
135
+ from herfy_auth import HerfyAuthClient
136
+
137
+ # For backend services that need to call the helpdesk API
138
+ auth_client = HerfyAuthClient(
139
+ control_center_url="https://control.herfy.com",
140
+ client_id="your-service-app-id",
141
+ client_secret="your-service-app-secret",
142
+ )
143
+
144
+ # Get a token for API calls
145
+ async def call_helpdesk_api():
146
+ tokens = await auth_client.get_client_credentials_token()
147
+
148
+ # Use the token to call other APIs
149
+ async with httpx.AsyncClient() as client:
150
+ response = await client.get(
151
+ "https://helpdesk-api.herfy.com/api/tickets",
152
+ headers={"Authorization": f"Bearer {tokens.access_token}"}
153
+ )
154
+ return response.json()
155
+ ```
156
+
157
+ ## API Reference
158
+
159
+ ### HerfyAuthClient
160
+
161
+ Main client class for authentication operations.
162
+
163
+ ```python
164
+ client = HerfyAuthClient(
165
+ control_center_url="https://control.herfy.com",
166
+ client_id="app-id", # Optional: for OAuth flows
167
+ client_secret="app-secret", # Optional: for OAuth flows
168
+ jwt_secret="shared-secret", # Optional: for local validation
169
+ )
170
+
171
+ # Validate a token
172
+ user = await client.validate_token(token)
173
+
174
+ # Get OAuth login URL
175
+ url = client.get_login_url(redirect_uri, state)
176
+
177
+ # Exchange authorization code
178
+ tokens = await client.exchange_code(code, redirect_uri)
179
+
180
+ # Get client credentials token
181
+ tokens = await client.get_client_credentials_token()
182
+
183
+ # Refresh a token
184
+ tokens = await client.refresh_token(refresh_token)
185
+ ```
186
+
187
+ ### UserInfo
188
+
189
+ User information model returned from token validation.
190
+
191
+ ```python
192
+ user = await client.validate_token(token)
193
+
194
+ user.id # User ID
195
+ user.email # Email address
196
+ user.roles # List of roles
197
+ user.org_roles # Organization roles
198
+ user.permissions # List of permissions
199
+ user.is_admin() # Check if admin
200
+ user.has_role("agent") # Check specific role
201
+ user.has_permission("tickets:read") # Check permission
202
+ ```
203
+
204
+ ### FastAPI Dependencies
205
+
206
+ ```python
207
+ from herfy_auth import get_current_user, get_optional_user, require_auth, require_admin
208
+
209
+ # Basic auth required
210
+ user = Depends(get_current_user)
211
+
212
+ # Optional auth (returns None if not authenticated)
213
+ user = Depends(get_optional_user)
214
+
215
+ # Require specific roles
216
+ user = Depends(require_auth(roles=["admin"]))
217
+
218
+ # Require any of multiple roles
219
+ user = Depends(require_auth(roles=["admin", "manager"], any_role=True))
220
+
221
+ # Require specific permissions
222
+ user = Depends(require_auth(permissions=["tickets:write"]))
223
+
224
+ # Convenience admin check
225
+ user = Depends(require_admin())
226
+ ```
227
+
228
+ ## Configuration
229
+
230
+ ### AuthConfig
231
+
232
+ ```python
233
+ from herfy_auth import AuthConfig
234
+
235
+ config = AuthConfig(
236
+ control_center_url="https://control.herfy.com",
237
+ client_id="app-id",
238
+ client_secret="app-secret",
239
+ jwt_secret="shared-secret",
240
+ jwt_algorithm="HS256",
241
+ token_validation_mode="local", # "local" or "remote"
242
+ cache_ttl_seconds=300,
243
+ )
244
+
245
+ # Or load from environment
246
+ config = AuthConfig.from_env()
247
+ ```
248
+
249
+ ### Environment Variables
250
+
251
+ | Variable | Description | Default |
252
+ |----------|-------------|---------|
253
+ | `CONTROL_CENTER_URL` | Control Center API URL | `http://localhost:8001` |
254
+ | `AUTH_CLIENT_ID` | OAuth client ID | - |
255
+ | `AUTH_CLIENT_SECRET` | OAuth client secret | - |
256
+ | `SECRET_KEY` / `JWT_SECRET` | JWT signing secret | - |
257
+ | `JWT_ALGORITHM` | JWT algorithm | `HS256` |
258
+ | `TOKEN_VALIDATION_MODE` | `local` or `remote` | `local` |
259
+ | `TOKEN_CACHE_TTL` | Cache TTL in seconds | `300` |
260
+
261
+ ## Token Validation Modes
262
+
263
+ ### Local Validation (Recommended)
264
+
265
+ Validates JWT tokens locally using a shared secret. Fast and doesn't require network calls.
266
+
267
+ ```bash
268
+ TOKEN_VALIDATION_MODE=local
269
+ SECRET_KEY=same-key-as-control-center
270
+ ```
271
+
272
+ ### Remote Validation
273
+
274
+ Validates tokens by calling the Control Center's `/oauth/userinfo` endpoint. Always up-to-date but requires network calls.
275
+
276
+ ```bash
277
+ TOKEN_VALIDATION_MODE=remote
278
+ CONTROL_CENTER_URL=https://control.herfy.com
279
+ ```
280
+
281
+ ## License
282
+
283
+ MIT
@@ -0,0 +1,27 @@
1
+ """
2
+ Herfy Auth SDK - Authentication client for integrating with the Control Center.
3
+
4
+ This SDK provides:
5
+ - Token validation against the Control Center
6
+ - OAuth2 authorization code flow helpers
7
+ - FastAPI middleware for protected routes
8
+ - User info retrieval from tokens
9
+ """
10
+
11
+ from .client import HerfyAuthClient
12
+ from .middleware import create_auth_middleware, require_auth
13
+ from .models import UserInfo, TokenResponse, AuthConfig
14
+ from .exceptions import AuthenticationError, TokenValidationError, ConfigurationError
15
+
16
+ __version__ = "1.0.0"
17
+ __all__ = [
18
+ "HerfyAuthClient",
19
+ "create_auth_middleware",
20
+ "require_auth",
21
+ "UserInfo",
22
+ "TokenResponse",
23
+ "AuthConfig",
24
+ "AuthenticationError",
25
+ "TokenValidationError",
26
+ "ConfigurationError",
27
+ ]