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.
- herfy_auth-1.0.0/PKG-INFO +317 -0
- herfy_auth-1.0.0/README.md +283 -0
- herfy_auth-1.0.0/herfy_auth/__init__.py +27 -0
- herfy_auth-1.0.0/herfy_auth/client.py +336 -0
- herfy_auth-1.0.0/herfy_auth/exceptions.py +25 -0
- herfy_auth-1.0.0/herfy_auth/middleware.py +287 -0
- herfy_auth-1.0.0/herfy_auth/models.py +148 -0
- herfy_auth-1.0.0/herfy_auth.egg-info/PKG-INFO +317 -0
- herfy_auth-1.0.0/herfy_auth.egg-info/SOURCES.txt +12 -0
- herfy_auth-1.0.0/herfy_auth.egg-info/dependency_links.txt +1 -0
- herfy_auth-1.0.0/herfy_auth.egg-info/requires.txt +14 -0
- herfy_auth-1.0.0/herfy_auth.egg-info/top_level.txt +1 -0
- herfy_auth-1.0.0/pyproject.toml +67 -0
- herfy_auth-1.0.0/setup.cfg +4 -0
|
@@ -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
|
+
]
|