authpi-admin 0.3.0__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.
Files changed (40) hide show
  1. authpi_admin/__init__.py +55 -0
  2. authpi_admin/_version.py +5 -0
  3. authpi_admin/client.py +155 -0
  4. authpi_admin/errors.py +218 -0
  5. authpi_admin/generated/__init__.py +28 -0
  6. authpi_admin/generated/models.py +380 -0
  7. authpi_admin/generated/resources/__init__.py +0 -0
  8. authpi_admin/generated/resources/accounts.py +157 -0
  9. authpi_admin/generated/resources/agents.py +177 -0
  10. authpi_admin/generated/resources/api_keys.py +213 -0
  11. authpi_admin/generated/resources/approvals.py +109 -0
  12. authpi_admin/generated/resources/auth_methods.py +148 -0
  13. authpi_admin/generated/resources/clients.py +197 -0
  14. authpi_admin/generated/resources/deliveries.py +83 -0
  15. authpi_admin/generated/resources/domains.py +194 -0
  16. authpi_admin/generated/resources/events.py +111 -0
  17. authpi_admin/generated/resources/groups.py +160 -0
  18. authpi_admin/generated/resources/invitations.py +202 -0
  19. authpi_admin/generated/resources/issuers.py +157 -0
  20. authpi_admin/generated/resources/members.py +154 -0
  21. authpi_admin/generated/resources/notes.py +192 -0
  22. authpi_admin/generated/resources/organizations.py +244 -0
  23. authpi_admin/generated/resources/sessions.py +125 -0
  24. authpi_admin/generated/resources/tokens.py +94 -0
  25. authpi_admin/generated/resources/trusted_devices.py +102 -0
  26. authpi_admin/generated/resources/users.py +224 -0
  27. authpi_admin/generated/resources/verifiers.py +102 -0
  28. authpi_admin/generated/resources/webhooks.py +167 -0
  29. authpi_admin/generated/scopes/__init__.py +0 -0
  30. authpi_admin/generated/scopes/agent_scope.py +84 -0
  31. authpi_admin/generated/scopes/issuer_scope.py +160 -0
  32. authpi_admin/generated/scopes/user_scope.py +102 -0
  33. authpi_admin/generated/scopes/webhook_scope.py +84 -0
  34. authpi_admin/http_client.py +305 -0
  35. authpi_admin/pagination.py +41 -0
  36. authpi_admin/py.typed +0 -0
  37. authpi_admin/user_agent.py +21 -0
  38. authpi_admin-0.3.0.dist-info/METADATA +285 -0
  39. authpi_admin-0.3.0.dist-info/RECORD +40 -0
  40. authpi_admin-0.3.0.dist-info/WHEEL +4 -0
@@ -0,0 +1,21 @@
1
+ """Build a User-Agent header string for the Admin SDK.
2
+
3
+ Format: ``authpi-admin-py/<sdk-version> Python/<python-version> (<platform>; <arch>)``
4
+
5
+ Example: ``authpi-admin-py/0.2.0 Python/3.11.5 (linux; x86_64)``
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import platform
11
+ import sys
12
+
13
+ _SDK_NAME = "authpi-admin-py"
14
+
15
+
16
+ def build_user_agent(sdk_version: str) -> str:
17
+ """Build the User-Agent string for this SDK."""
18
+ py_version = f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}"
19
+ system = platform.system().lower() # linux, darwin, windows
20
+ machine = platform.machine().lower() # x86_64, arm64, etc.
21
+ return f"{_SDK_NAME}/{sdk_version} Python/{py_version} ({system}; {machine})"
@@ -0,0 +1,285 @@
1
+ Metadata-Version: 2.4
2
+ Name: authpi-admin
3
+ Version: 0.3.0
4
+ Summary: Official Python Admin SDK for AuthPI Core API
5
+ Project-URL: Homepage, https://authpi.com
6
+ Project-URL: Documentation, https://docs.authpi.com/sdk/python/admin
7
+ Project-URL: Repository, https://github.com/arbfay/authpi
8
+ Author-email: AuthPI <hello@authpi.com>
9
+ License: MIT
10
+ Keywords: admin,api,authentication,authorization,authpi,sdk
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Framework :: AsyncIO
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Security
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Classifier: Typing :: Typed
22
+ Requires-Python: >=3.11
23
+ Requires-Dist: httpx>=0.27.0
24
+ Requires-Dist: pydantic>=2.0.0
25
+ Provides-Extra: dev
26
+ Requires-Dist: mypy>=1.13.0; extra == 'dev'
27
+ Requires-Dist: pytest-asyncio>=0.24.0; extra == 'dev'
28
+ Requires-Dist: pytest-httpx>=0.34.0; extra == 'dev'
29
+ Requires-Dist: pytest>=8.0.0; extra == 'dev'
30
+ Requires-Dist: ruff>=0.8.0; extra == 'dev'
31
+ Description-Content-Type: text/markdown
32
+
33
+ # authpi-admin
34
+
35
+ Official Python Admin SDK for the AuthPI Core API.
36
+
37
+ **Requirements:** Python 3.11+, async-only (`httpx` + `asyncio`)
38
+
39
+ ## Installation
40
+
41
+ ```bash
42
+ pip install authpi-admin
43
+ ```
44
+
45
+ ## Quick Start
46
+
47
+ ```python
48
+ from authpi_admin import AuthPIAdmin
49
+
50
+ async with AuthPIAdmin(api_key="key_xxx") as admin:
51
+ # List issuers
52
+ page = await admin.issuers.list(limit=10)
53
+ print(page.data)
54
+
55
+ # Scope into an issuer and manage users
56
+ users = await admin.issuer("iss_xxx").users.list()
57
+
58
+ # Auto-paginate
59
+ async for user in admin.issuer("iss_xxx").users.list_all():
60
+ print(user)
61
+
62
+ # Create a user
63
+ user = await admin.issuer("iss_xxx").users.create({
64
+ "email": "alice@example.com",
65
+ "display_name": "Alice",
66
+ })
67
+ ```
68
+
69
+ ## Authentication
70
+
71
+ ### API Key (default)
72
+
73
+ ```python
74
+ admin = AuthPIAdmin(api_key="key_xxx")
75
+ ```
76
+
77
+ ### Bearer Token
78
+
79
+ For server-side applications authenticating on behalf of a user session:
80
+
81
+ ```python
82
+ admin = AuthPIAdmin(
83
+ access_token="tok_xxx",
84
+ account_id="acc_xxx",
85
+ )
86
+ ```
87
+
88
+ With optional token refresh callback:
89
+
90
+ ```python
91
+ async def refresh():
92
+ new_tokens = await my_refresh_logic()
93
+ return {"access_token": new_tokens.access_token}
94
+
95
+ admin = AuthPIAdmin(
96
+ access_token="tok_xxx",
97
+ account_id="acc_xxx",
98
+ on_token_expired=refresh,
99
+ )
100
+ ```
101
+
102
+ When `on_token_expired` is provided, the SDK calls it on 401 responses and retries the request with the new token. Concurrent 401s are deduplicated — only one refresh runs at a time.
103
+
104
+ ## Scoped Client Pattern
105
+
106
+ The SDK mirrors the API's resource hierarchy. Navigate with chained accessors:
107
+
108
+ ```python
109
+ # Account-level resources
110
+ await admin.issuers.list()
111
+ await admin.webhooks.create({"url": "https://..."})
112
+ await admin.events.list(limit=50)
113
+
114
+ # Issuer scope
115
+ iss = admin.issuer("iss_xxx")
116
+ await iss.users.list()
117
+ await iss.agents.create({"name": "bot"})
118
+ await iss.clients.list()
119
+ await iss.organizations.list()
120
+
121
+ # User scope (nested under issuer)
122
+ usr = admin.issuer("iss_xxx").user("usr_xxx")
123
+ await usr.get()
124
+ await usr.sessions.list()
125
+ await usr.tokens.list()
126
+ await usr.trusted_devices.list()
127
+ await usr.verifiers.list()
128
+
129
+ # Webhook scope
130
+ wh = admin.webhook("wh_xxx")
131
+ await wh.get()
132
+ await wh.deliveries.list()
133
+ ```
134
+
135
+ ## Pagination
136
+
137
+ List endpoints return a `Page` with cursor-based pagination:
138
+
139
+ ```python
140
+ # Manual pagination
141
+ page = await admin.issuer("iss_xxx").users.list(limit=25)
142
+ print(page.data) # list[dict]
143
+ print(page.has_more) # bool
144
+ print(page.next_cursor) # str | None
145
+
146
+ # Fetch next page
147
+ if page.has_more:
148
+ next_page = await admin.issuer("iss_xxx").users.list(
149
+ limit=25, cursor=page.next_cursor
150
+ )
151
+
152
+ # Auto-pagination (yields individual items across all pages)
153
+ async for user in admin.issuer("iss_xxx").users.list_all():
154
+ print(user)
155
+ ```
156
+
157
+ ## Retries
158
+
159
+ Read-only requests (GET, HEAD, OPTIONS) are automatically retried on 429, 502, 503, and 504 responses with exponential backoff. The `Retry-After` header is respected when present.
160
+
161
+ ```python
162
+ # Default: retries enabled (3 attempts, 1s base delay, exponential backoff)
163
+ admin = AuthPIAdmin(api_key="key_xxx")
164
+
165
+ # Disable retries
166
+ admin = AuthPIAdmin(api_key="key_xxx", retries=False)
167
+
168
+ # Custom retry config
169
+ admin = AuthPIAdmin(
170
+ api_key="key_xxx",
171
+ retries={"limit": 5, "delay": 0.5, "backoff": "linear"},
172
+ )
173
+ ```
174
+
175
+ Mutations (POST, PATCH, DELETE) are never retried automatically. Use idempotency keys and handle retries explicitly for writes.
176
+
177
+ ## ETags & Optimistic Concurrency
178
+
179
+ GET responses include an `_etag` field. Pass it back on updates to prevent overwriting concurrent changes:
180
+
181
+ ```python
182
+ user = await admin.issuer("iss_xxx").user("usr_xxx").get()
183
+
184
+ # Conditional update — fails with PreconditionFailedError if modified
185
+ await admin.issuer("iss_xxx").users.update(
186
+ "usr_xxx",
187
+ {"display_name": "Bob"},
188
+ if_match=user.get("_etag"),
189
+ )
190
+ ```
191
+
192
+ ## Error Handling
193
+
194
+ The SDK maps HTTP status codes to specific error classes:
195
+
196
+ ```python
197
+ from authpi_admin import (
198
+ NotFoundError,
199
+ ValidationError,
200
+ AuthenticationError,
201
+ RateLimitError,
202
+ PreconditionFailedError,
203
+ )
204
+
205
+ try:
206
+ await admin.issuer("iss_xxx").user("usr_xxx").get()
207
+ except NotFoundError:
208
+ print("User not found")
209
+ except ValidationError as err:
210
+ print("Validation failed:", err.fields)
211
+ except RateLimitError as err:
212
+ print(f"Retry after {err.retry_after} seconds")
213
+ except AuthenticationError:
214
+ print("Invalid credentials")
215
+ ```
216
+
217
+ ### Error Hierarchy
218
+
219
+ | Error | Status | Extra Fields | Retryable |
220
+ |-------|--------|--------------|-----------|
221
+ | `ApiError` | — | `error`, `error_description`, `status_code`, `retryable`, `reference`, `raw_body` | — |
222
+ | `ValidationError` | 400, 422 | `fields` | No |
223
+ | `AuthenticationError` | 401 | — | No |
224
+ | `ForbiddenError` | 403 | — | No |
225
+ | `NotFoundError` | 404 | — | No |
226
+ | `ConflictError` | 409 | — | No |
227
+ | `PreconditionFailedError` | 412 | `current_etag` | No |
228
+ | `RateLimitError` | 429 | `retry_after` | Yes |
229
+ | `InternalServerError` | 500 | — | No |
230
+ | `BadGatewayError` | 502 | — | Yes |
231
+ | `ServiceUnavailableError` | 503 | — | Yes |
232
+ | `GatewayTimeoutError` | 504 | — | Yes |
233
+ | `UnexpectedError` | other | — | No |
234
+ | `ClosedClientError` | — | — | No |
235
+
236
+ ## Configuration
237
+
238
+ ```python
239
+ from authpi_admin import AuthPIAdmin
240
+
241
+ admin = AuthPIAdmin(
242
+ api_key="key_xxx", # or access_token + account_id
243
+ base_url="https://api.authpi.dev", # default
244
+ timeout=30.0, # default, in seconds
245
+ default_headers={"X-Custom": "value"}, # optional extra headers
246
+ retries=True, # default (or False, or dict)
247
+ )
248
+ ```
249
+
250
+ ### Custom httpx Client
251
+
252
+ Inject a pre-configured `httpx.AsyncClient` for advanced use cases (proxies, certificates, connection pooling):
253
+
254
+ ```python
255
+ import httpx
256
+ from authpi_admin import AuthPIAdmin
257
+
258
+ async with httpx.AsyncClient(proxies="http://proxy:8080") as http:
259
+ admin = AuthPIAdmin(api_key="key_xxx", http_client=http)
260
+ await admin.issuers.list()
261
+ ```
262
+
263
+ ### Context Manager
264
+
265
+ The SDK supports async context managers for clean resource cleanup:
266
+
267
+ ```python
268
+ async with AuthPIAdmin(api_key="key_xxx") as admin:
269
+ await admin.issuers.list()
270
+ # httpx client is closed automatically
271
+ ```
272
+
273
+ Or close manually:
274
+
275
+ ```python
276
+ admin = AuthPIAdmin(api_key="key_xxx")
277
+ try:
278
+ await admin.issuers.list()
279
+ finally:
280
+ await admin.close()
281
+ ```
282
+
283
+ ## License
284
+
285
+ MIT
@@ -0,0 +1,40 @@
1
+ authpi_admin/__init__.py,sha256=2C5Bh6FDEFWpHT8WRNpS3hkrRB58qBmpiUKHvreMaIo,1376
2
+ authpi_admin/_version.py,sha256=Ev00lZsiXxyvPxcsC6QBTyMzWYtUIP2jbCYqmf9Q2G0,154
3
+ authpi_admin/client.py,sha256=ThHq_OFMu7-sSqqzZ0VePBjLkvT_KNF70iGIYcCxuUM,5358
4
+ authpi_admin/errors.py,sha256=J_gW7uqGYB6B3ww-2BFI86KawyObSC6gDq-lJQ-uqmA,6139
5
+ authpi_admin/http_client.py,sha256=ktN5tpGio1AzIoobg-v4MuBInwh4yvt_9yTZBH0XjVg,10654
6
+ authpi_admin/pagination.py,sha256=Mmb75qEN_wZ0YzCq-oz5EG-9zf93uyR2ydRdvv-6gYE,992
7
+ authpi_admin/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ authpi_admin/user_agent.py,sha256=WgFss0m362eVHBoxW5HZVmW_C5boPTtCsf5K21M9EVE,715
9
+ authpi_admin/generated/__init__.py,sha256=UdYsTfHZInAbqsg9dq_DfifKFoBMFvjzU40f1ohZWug,1645
10
+ authpi_admin/generated/models.py,sha256=shYd_IuEHbLe5P-aYp7vR8olNlUK2-UiXOMCjIrnoRI,9652
11
+ authpi_admin/generated/resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
+ authpi_admin/generated/resources/accounts.py,sha256=3L2VK_-aL1NkxgEkARjk5T2ma_zFGdq-fHkLj18zj40,4832
13
+ authpi_admin/generated/resources/agents.py,sha256=ftyjSduF2M6E7AUAg9lLinxqwUJNfVzVm2xtx1j2mtc,5499
14
+ authpi_admin/generated/resources/api_keys.py,sha256=dWPWrX7Pgfi8UbbxeWeqNgkqehNsJ40KD16rV43lVdI,6532
15
+ authpi_admin/generated/resources/approvals.py,sha256=L02ZFApbwg1jeBe-_5bDTbILbUZ4Nhv6hBq4bpZAORw,3415
16
+ authpi_admin/generated/resources/auth_methods.py,sha256=GIQ6qCwqtbr-nMmdl1lmNCr3t2aqVFJzX9USpKYMLZU,4512
17
+ authpi_admin/generated/resources/clients.py,sha256=hccCOBJ1IGVCIwrGDh-gI63VyPJwlBM4KwtNFQT819M,6061
18
+ authpi_admin/generated/resources/deliveries.py,sha256=Vs-AmSKBEWgucM9sZUSeUsvneXYaU9a_6L_-iWTZ9W0,2688
19
+ authpi_admin/generated/resources/domains.py,sha256=X-Xj0gqR31sRNccxEvWseggWeIyR3q0dqaUFan5T01M,5989
20
+ authpi_admin/generated/resources/events.py,sha256=atUfR6br_dwIRygVDKarA28t9c11SDRyBrCCELXhKSM,3582
21
+ authpi_admin/generated/resources/groups.py,sha256=rRzFgnkzrKN9rYqGh4ghlcwSeWiPqdyV53GO2mg87oQ,4904
22
+ authpi_admin/generated/resources/invitations.py,sha256=_Uufa5TuSnw1xQuW5-FiOjYh-vdbEruTj33mKx4sdXQ,6353
23
+ authpi_admin/generated/resources/issuers.py,sha256=a-dXIpvS2xHbUJxI4a1aQqyqr3qsPF_njP7AOwz6t6o,4776
24
+ authpi_admin/generated/resources/members.py,sha256=JIoAUR6MxxqCkHCVDpyCs_qlZE6KvkgOXfVXwWtBpV4,4731
25
+ authpi_admin/generated/resources/notes.py,sha256=76xTKxtLmbbwOtgsnJQNY1QbnveecD2ly2zBJ2kyKV0,6034
26
+ authpi_admin/generated/resources/organizations.py,sha256=I93MJDQdOCzFaADJk7IdcxHGNr5E7SfGr7A04WUWF1s,7811
27
+ authpi_admin/generated/resources/sessions.py,sha256=Bmx-RycxHELhulZ62ZvEYpbU5dnC43dTTl4jShqJRwY,3981
28
+ authpi_admin/generated/resources/tokens.py,sha256=RvHcuKC7uErcDRCvkLoI9PyKY-FUTvdnM62aUyD0ccs,2918
29
+ authpi_admin/generated/resources/trusted_devices.py,sha256=0_BGxY812JM9g0LeCHNvInrGHuGbrIHZ6X6XVm8PwnA,3099
30
+ authpi_admin/generated/resources/users.py,sha256=tEB-z0r7_s2VCTEqaXEcxBmRZfu72jYQhgKRE8ZeSaU,6996
31
+ authpi_admin/generated/resources/verifiers.py,sha256=zw3_8__nr-hmfaS27pH_tcPGn3TtJ-oXJCF5IqYdkkQ,3084
32
+ authpi_admin/generated/resources/webhooks.py,sha256=BMc1OLLW1TrsGwdI8DoPvu2CybVE5uJ4WLq-3WOWnOk,5105
33
+ authpi_admin/generated/scopes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
34
+ authpi_admin/generated/scopes/agent_scope.py,sha256=xNiZO99PsOBr5cAz3mxYXIBjdteH5GzJzHEVSTWx3PM,2543
35
+ authpi_admin/generated/scopes/issuer_scope.py,sha256=CJN3XUqEDc5o1bQHfcr_j3qNqxekGwEOjZnGWZxGW40,5859
36
+ authpi_admin/generated/scopes/user_scope.py,sha256=2IPkqtK0pBFyi0VR6tVEPt0oXoUtXHyv9BsSxQjwibc,3330
37
+ authpi_admin/generated/scopes/webhook_scope.py,sha256=nQvpG-1ohDF0tsMJWzIJ6XSwu7DIk2TmoIErvqXLRT4,2576
38
+ authpi_admin-0.3.0.dist-info/METADATA,sha256=v3_hmviJWJSYsNPNAewsO5Iabxc5N3UNBu1gOZdtwgg,7684
39
+ authpi_admin-0.3.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
40
+ authpi_admin-0.3.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.29.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any