phzyx-auth 0.1.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.
- phzyx_auth-0.1.0/.gitignore +87 -0
- phzyx_auth-0.1.0/PKG-INFO +116 -0
- phzyx_auth-0.1.0/README.md +88 -0
- phzyx_auth-0.1.0/pyproject.toml +39 -0
- phzyx_auth-0.1.0/src/phzyx/auth/__init__.py +141 -0
- phzyx_auth-0.1.0/src/phzyx/auth/adapters/__init__.py +19 -0
- phzyx_auth-0.1.0/src/phzyx/auth/adapters/fastapi.py +638 -0
- phzyx_auth-0.1.0/src/phzyx/auth/adapters/litestar.py +280 -0
- phzyx_auth-0.1.0/src/phzyx/auth/admin_bridge.py +83 -0
- phzyx_auth-0.1.0/src/phzyx/auth/api_keys.py +94 -0
- phzyx_auth-0.1.0/src/phzyx/auth/audit.py +36 -0
- phzyx_auth-0.1.0/src/phzyx/auth/cli.py +43 -0
- phzyx_auth-0.1.0/src/phzyx/auth/config.py +92 -0
- phzyx_auth-0.1.0/src/phzyx/auth/crypto.py +19 -0
- phzyx_auth-0.1.0/src/phzyx/auth/csrf.py +45 -0
- phzyx_auth-0.1.0/src/phzyx/auth/decorators.py +116 -0
- phzyx_auth-0.1.0/src/phzyx/auth/errors.py +64 -0
- phzyx_auth-0.1.0/src/phzyx/auth/guards.py +67 -0
- phzyx_auth-0.1.0/src/phzyx/auth/models.py +238 -0
- phzyx_auth-0.1.0/src/phzyx/auth/oauth.py +249 -0
- phzyx_auth-0.1.0/src/phzyx/auth/orm_stores.py +436 -0
- phzyx_auth-0.1.0/src/phzyx/auth/passkeys.py +351 -0
- phzyx_auth-0.1.0/src/phzyx/auth/password.py +56 -0
- phzyx_auth-0.1.0/src/phzyx/auth/principal.py +73 -0
- phzyx_auth-0.1.0/src/phzyx/auth/rate_limit.py +76 -0
- phzyx_auth-0.1.0/src/phzyx/auth/rbac.py +75 -0
- phzyx_auth-0.1.0/src/phzyx/auth/service.py +956 -0
- phzyx_auth-0.1.0/src/phzyx/auth/service_async.py +77 -0
- phzyx_auth-0.1.0/src/phzyx/auth/sessions.py +117 -0
- phzyx_auth-0.1.0/src/phzyx/auth/tokens.py +158 -0
- phzyx_auth-0.1.0/src/phzyx/auth/totp.py +105 -0
- phzyx_auth-0.1.0/tests/test_auth_fastapi_mount.py +184 -0
- phzyx_auth-0.1.0/tests/test_auth_foundation.py +165 -0
- phzyx_auth-0.1.0/tests/test_auth_litestar.py +84 -0
- phzyx_auth-0.1.0/tests/test_auth_orm_stores.py +97 -0
- phzyx_auth-0.1.0/tests/test_auth_service_flows.py +193 -0
- phzyx_auth-0.1.0/tests/test_oauth_mfa.py +150 -0
- phzyx_auth-0.1.0/tests/test_passkeys.py +97 -0
- phzyx_auth-0.1.0/tests/test_rate_limit_redis.py +70 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
.Python
|
|
7
|
+
*.egg-info/
|
|
8
|
+
.eggs/
|
|
9
|
+
dist/
|
|
10
|
+
!packages/admin/web/dist/
|
|
11
|
+
!packages/admin/web/dist/**
|
|
12
|
+
build/
|
|
13
|
+
*.egg
|
|
14
|
+
|
|
15
|
+
# Virtual environments
|
|
16
|
+
.venv/
|
|
17
|
+
venv/
|
|
18
|
+
ENV/
|
|
19
|
+
examples/**/.venv/
|
|
20
|
+
|
|
21
|
+
# uv / packaging
|
|
22
|
+
# uv.lock is committed for reproducible workspace installs
|
|
23
|
+
|
|
24
|
+
# Testing / coverage
|
|
25
|
+
.pytest_cache/
|
|
26
|
+
.hypothesis/
|
|
27
|
+
.coverage
|
|
28
|
+
.coverage.*
|
|
29
|
+
coverage.xml
|
|
30
|
+
coverage.json
|
|
31
|
+
htmlcov/
|
|
32
|
+
.mypy_cache/
|
|
33
|
+
.ruff_cache/
|
|
34
|
+
.dmypy.json
|
|
35
|
+
dmypy.json
|
|
36
|
+
.pytype/
|
|
37
|
+
.pyre/
|
|
38
|
+
|
|
39
|
+
# Type checkers / IDE
|
|
40
|
+
.idea/
|
|
41
|
+
.vscode/
|
|
42
|
+
*.swp
|
|
43
|
+
*.swo
|
|
44
|
+
*~
|
|
45
|
+
|
|
46
|
+
# OS
|
|
47
|
+
.DS_Store
|
|
48
|
+
Thumbs.db
|
|
49
|
+
|
|
50
|
+
# Env / secrets
|
|
51
|
+
.env
|
|
52
|
+
.env.*
|
|
53
|
+
!.env.example
|
|
54
|
+
|
|
55
|
+
# Node (AdminBoard SPA + sites)
|
|
56
|
+
node_modules/
|
|
57
|
+
.pnpm-store/
|
|
58
|
+
packages/admin/web/node_modules/
|
|
59
|
+
# Built SPA is committed for offline wheel/demo convenience (M4);
|
|
60
|
+
# rebuild via packages/admin/web `npm run build` when sources change.
|
|
61
|
+
# packages/admin/web/dist/
|
|
62
|
+
|
|
63
|
+
# Local tooling
|
|
64
|
+
.justfile.local
|
|
65
|
+
packages/admin/web/node_modules/
|
|
66
|
+
dist-release/
|
|
67
|
+
|
|
68
|
+
# Local demo SQLite
|
|
69
|
+
examples/**/*.db
|
|
70
|
+
examples/**/media/
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
# Admin web tooling
|
|
74
|
+
packages/admin/web/test-results/
|
|
75
|
+
packages/admin/web/playwright-report/
|
|
76
|
+
packages/admin/web/blob-report/
|
|
77
|
+
|
|
78
|
+
# Private: research, design plans, AI agent helpers (local only — do not push)
|
|
79
|
+
# Files remain on disk; they are untracked for remotes.
|
|
80
|
+
research/
|
|
81
|
+
AGENTS.md
|
|
82
|
+
AGENT_TO_AGENT.md
|
|
83
|
+
docs/agent-rules.md
|
|
84
|
+
.cursor/
|
|
85
|
+
.claude/
|
|
86
|
+
.grok/
|
|
87
|
+
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: phzyx-auth
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Phzyx Auth — secure-by-default identity, sessions, JWT, API keys, RBAC (Forge battery)
|
|
5
|
+
Project-URL: Homepage, https://phzyx.xyz
|
|
6
|
+
Project-URL: Repository, https://github.com/phzyxyz/forge
|
|
7
|
+
Author: Athul Nandaswaroop
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
Requires-Python: >=3.11
|
|
10
|
+
Requires-Dist: argon2-cffi>=23
|
|
11
|
+
Requires-Dist: phzyx-forge<0.2,>=0.1.0
|
|
12
|
+
Requires-Dist: pydantic>=2
|
|
13
|
+
Requires-Dist: pyjwt>=2.8
|
|
14
|
+
Provides-Extra: fastapi
|
|
15
|
+
Requires-Dist: fastapi>=0.115; extra == 'fastapi'
|
|
16
|
+
Provides-Extra: litestar
|
|
17
|
+
Requires-Dist: litestar>=2.12; extra == 'litestar'
|
|
18
|
+
Provides-Extra: mfa
|
|
19
|
+
Requires-Dist: pyotp>=2.9; extra == 'mfa'
|
|
20
|
+
Provides-Extra: oauth
|
|
21
|
+
Requires-Dist: authlib>=1.3; extra == 'oauth'
|
|
22
|
+
Requires-Dist: httpx>=0.27; extra == 'oauth'
|
|
23
|
+
Provides-Extra: redis
|
|
24
|
+
Requires-Dist: redis>=5; extra == 'redis'
|
|
25
|
+
Provides-Extra: webauthn
|
|
26
|
+
Requires-Dist: webauthn>=2.0; extra == 'webauthn'
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
|
|
29
|
+
# phzyx-auth
|
|
30
|
+
|
|
31
|
+
Secure-by-default authentication & authorization for Phzyx apps and AdminBoard.
|
|
32
|
+
|
|
33
|
+
**Public battery** for Forge (depends on `phzyx-forge` on PyPI).
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
uv add 'phzyx-forge[auth]'
|
|
37
|
+
# or
|
|
38
|
+
uv add 'phzyx-auth[fastapi]'
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Status (0.1.0)
|
|
42
|
+
|
|
43
|
+
**Phase A + B shipped** (memory backends; ORM-backed stores next):
|
|
44
|
+
|
|
45
|
+
| Area | What you get |
|
|
46
|
+
|------|----------------|
|
|
47
|
+
| Passwords | Argon2id, policy min length |
|
|
48
|
+
| Sessions | Opaque cookie sessions (hashed at rest), idle + absolute TTL |
|
|
49
|
+
| JWT | HS256 access + rotating refresh |
|
|
50
|
+
| API keys | `phx_` prefix, scopes, list/revoke |
|
|
51
|
+
| RBAC | Groups/Permissions models, Principal, `ensure_*` + Depends + decorators |
|
|
52
|
+
| Lockout | Failed-login counter + rate limits + audit log |
|
|
53
|
+
| Reset / change | Forgot/reset (anti-enum), change password, revoke sessions |
|
|
54
|
+
| Email verify | Token issue + verify (`email_verified` flag) |
|
|
55
|
+
| CSRF | Double-submit cookie + `X-CSRF-Token` for session mutations |
|
|
56
|
+
| WebSocket | `websocket_principal` (cookie / Bearer / API key, close 4401) |
|
|
57
|
+
| AdminBoard | `PhzyxAuthz` permission bridge |
|
|
58
|
+
| CLI | `phzyx-auth create-superuser` |
|
|
59
|
+
|
|
60
|
+
**Later:** OAuth IdPs (Phase D stub in `oauth.py`), MFA/passkeys (E), orgs (F), Redis rate limit, ORM session store.
|
|
61
|
+
|
|
62
|
+
## Quick start (FastAPI)
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
from fastapi import Depends, FastAPI
|
|
66
|
+
from phzyx.auth import AuthConfig, AuthService, Principal
|
|
67
|
+
from phzyx.auth.adapters.fastapi import mount_auth, require_user
|
|
68
|
+
|
|
69
|
+
app = FastAPI()
|
|
70
|
+
svc = AuthService(
|
|
71
|
+
config=AuthConfig(
|
|
72
|
+
secret="use-PHZYX_AUTH_SECRET-32+bytes-in-prod!!",
|
|
73
|
+
production=False,
|
|
74
|
+
cookie_secure=False,
|
|
75
|
+
)
|
|
76
|
+
)
|
|
77
|
+
mount_auth(app, svc)
|
|
78
|
+
|
|
79
|
+
@app.get("/private")
|
|
80
|
+
async def private(user: Principal = Depends(require_user)):
|
|
81
|
+
return {"email": user.email}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
# create staff superuser (in-memory unless you wire persistence)
|
|
86
|
+
phzyx-auth create-superuser --email admin@example.com --password 'longpassword1'
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### SPA cookie flow
|
|
90
|
+
|
|
91
|
+
1. `POST /auth/login` → sets `phzyx_session` (HttpOnly) + `phzyx_csrf` + returns `csrf_token`
|
|
92
|
+
2. Mutating requests with the session cookie must send header `X-CSRF-Token: <csrf_token>`
|
|
93
|
+
3. Bearer JWT / `X-API-Key` skip CSRF
|
|
94
|
+
|
|
95
|
+
### In-body checks (no middleware)
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
from phzyx.auth.guards import ensure_authenticated, ensure_permissions
|
|
99
|
+
|
|
100
|
+
p = svc.resolve_principal(session_token=cookie, authorization=authz, api_key=key)
|
|
101
|
+
user = ensure_authenticated(p)
|
|
102
|
+
ensure_permissions(user, ["posts:create"])
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Security defaults
|
|
106
|
+
|
|
107
|
+
- Argon2id hashing
|
|
108
|
+
- Secrets ≥ 32 bytes (HS256 / pepper)
|
|
109
|
+
- Opaque sessions + short JWT access
|
|
110
|
+
- API keys hashed at rest
|
|
111
|
+
- Lockout + IP/email rate limits
|
|
112
|
+
- Password reset anti-enumeration
|
|
113
|
+
- Extensible `AbstractUser`
|
|
114
|
+
|
|
115
|
+
**Research (do not re-derive):** [`research/plan/20_phzyx_auth.md`](../../research/plan/20_phzyx_auth.md)
|
|
116
|
+
**Tracker:** [`PHZYX_ROADMAP.html`](../../PHZYX_ROADMAP.html) track **AUTH**.
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# phzyx-auth
|
|
2
|
+
|
|
3
|
+
Secure-by-default authentication & authorization for Phzyx apps and AdminBoard.
|
|
4
|
+
|
|
5
|
+
**Public battery** for Forge (depends on `phzyx-forge` on PyPI).
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
uv add 'phzyx-forge[auth]'
|
|
9
|
+
# or
|
|
10
|
+
uv add 'phzyx-auth[fastapi]'
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Status (0.1.0)
|
|
14
|
+
|
|
15
|
+
**Phase A + B shipped** (memory backends; ORM-backed stores next):
|
|
16
|
+
|
|
17
|
+
| Area | What you get |
|
|
18
|
+
|------|----------------|
|
|
19
|
+
| Passwords | Argon2id, policy min length |
|
|
20
|
+
| Sessions | Opaque cookie sessions (hashed at rest), idle + absolute TTL |
|
|
21
|
+
| JWT | HS256 access + rotating refresh |
|
|
22
|
+
| API keys | `phx_` prefix, scopes, list/revoke |
|
|
23
|
+
| RBAC | Groups/Permissions models, Principal, `ensure_*` + Depends + decorators |
|
|
24
|
+
| Lockout | Failed-login counter + rate limits + audit log |
|
|
25
|
+
| Reset / change | Forgot/reset (anti-enum), change password, revoke sessions |
|
|
26
|
+
| Email verify | Token issue + verify (`email_verified` flag) |
|
|
27
|
+
| CSRF | Double-submit cookie + `X-CSRF-Token` for session mutations |
|
|
28
|
+
| WebSocket | `websocket_principal` (cookie / Bearer / API key, close 4401) |
|
|
29
|
+
| AdminBoard | `PhzyxAuthz` permission bridge |
|
|
30
|
+
| CLI | `phzyx-auth create-superuser` |
|
|
31
|
+
|
|
32
|
+
**Later:** OAuth IdPs (Phase D stub in `oauth.py`), MFA/passkeys (E), orgs (F), Redis rate limit, ORM session store.
|
|
33
|
+
|
|
34
|
+
## Quick start (FastAPI)
|
|
35
|
+
|
|
36
|
+
```python
|
|
37
|
+
from fastapi import Depends, FastAPI
|
|
38
|
+
from phzyx.auth import AuthConfig, AuthService, Principal
|
|
39
|
+
from phzyx.auth.adapters.fastapi import mount_auth, require_user
|
|
40
|
+
|
|
41
|
+
app = FastAPI()
|
|
42
|
+
svc = AuthService(
|
|
43
|
+
config=AuthConfig(
|
|
44
|
+
secret="use-PHZYX_AUTH_SECRET-32+bytes-in-prod!!",
|
|
45
|
+
production=False,
|
|
46
|
+
cookie_secure=False,
|
|
47
|
+
)
|
|
48
|
+
)
|
|
49
|
+
mount_auth(app, svc)
|
|
50
|
+
|
|
51
|
+
@app.get("/private")
|
|
52
|
+
async def private(user: Principal = Depends(require_user)):
|
|
53
|
+
return {"email": user.email}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
# create staff superuser (in-memory unless you wire persistence)
|
|
58
|
+
phzyx-auth create-superuser --email admin@example.com --password 'longpassword1'
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### SPA cookie flow
|
|
62
|
+
|
|
63
|
+
1. `POST /auth/login` → sets `phzyx_session` (HttpOnly) + `phzyx_csrf` + returns `csrf_token`
|
|
64
|
+
2. Mutating requests with the session cookie must send header `X-CSRF-Token: <csrf_token>`
|
|
65
|
+
3. Bearer JWT / `X-API-Key` skip CSRF
|
|
66
|
+
|
|
67
|
+
### In-body checks (no middleware)
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
from phzyx.auth.guards import ensure_authenticated, ensure_permissions
|
|
71
|
+
|
|
72
|
+
p = svc.resolve_principal(session_token=cookie, authorization=authz, api_key=key)
|
|
73
|
+
user = ensure_authenticated(p)
|
|
74
|
+
ensure_permissions(user, ["posts:create"])
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Security defaults
|
|
78
|
+
|
|
79
|
+
- Argon2id hashing
|
|
80
|
+
- Secrets ≥ 32 bytes (HS256 / pepper)
|
|
81
|
+
- Opaque sessions + short JWT access
|
|
82
|
+
- API keys hashed at rest
|
|
83
|
+
- Lockout + IP/email rate limits
|
|
84
|
+
- Password reset anti-enumeration
|
|
85
|
+
- Extensible `AbstractUser`
|
|
86
|
+
|
|
87
|
+
**Research (do not re-derive):** [`research/plan/20_phzyx_auth.md`](../../research/plan/20_phzyx_auth.md)
|
|
88
|
+
**Tracker:** [`PHZYX_ROADMAP.html`](../../PHZYX_ROADMAP.html) track **AUTH**.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "phzyx-auth"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Phzyx Auth — secure-by-default identity, sessions, JWT, API keys, RBAC (Forge battery)"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.11"
|
|
7
|
+
license = "MIT"
|
|
8
|
+
authors = [{ name = "Athul Nandaswaroop" }]
|
|
9
|
+
dependencies = [
|
|
10
|
+
"phzyx-forge>=0.1.0,<0.2",
|
|
11
|
+
"pydantic>=2",
|
|
12
|
+
"argon2-cffi>=23",
|
|
13
|
+
"PyJWT>=2.8",
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
[project.optional-dependencies]
|
|
17
|
+
redis = ["redis>=5"]
|
|
18
|
+
oauth = ["authlib>=1.3", "httpx>=0.27"]
|
|
19
|
+
mfa = ["pyotp>=2.9"]
|
|
20
|
+
webauthn = ["webauthn>=2.0"]
|
|
21
|
+
fastapi = ["fastapi>=0.115"]
|
|
22
|
+
litestar = ["litestar>=2.12"]
|
|
23
|
+
|
|
24
|
+
[project.scripts]
|
|
25
|
+
phzyx-auth = "phzyx.auth.cli:main"
|
|
26
|
+
|
|
27
|
+
[project.urls]
|
|
28
|
+
Homepage = "https://phzyx.xyz"
|
|
29
|
+
Repository = "https://github.com/phzyxyz/forge"
|
|
30
|
+
|
|
31
|
+
[tool.uv.sources]
|
|
32
|
+
phzyx-forge = { workspace = true }
|
|
33
|
+
|
|
34
|
+
[build-system]
|
|
35
|
+
requires = ["hatchling"]
|
|
36
|
+
build-backend = "hatchling.build"
|
|
37
|
+
|
|
38
|
+
[tool.hatch.build.targets.wheel]
|
|
39
|
+
packages = ["src/phzyx"]
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"""Phzyx Auth — identity, sessions, JWT, API keys, guards (batteries optional)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from phzyx.auth.admin_bridge import PhzyxAuthz, PhzyxFieldAuthz
|
|
8
|
+
from phzyx.auth.api_keys import IssuedAPIKey, MemoryAPIKeyStore
|
|
9
|
+
from phzyx.auth.audit import AuditLog
|
|
10
|
+
from phzyx.auth.config import AuthConfig
|
|
11
|
+
from phzyx.auth.decorators import (
|
|
12
|
+
require_auth,
|
|
13
|
+
require_permissions,
|
|
14
|
+
require_scopes,
|
|
15
|
+
require_staff,
|
|
16
|
+
require_superuser,
|
|
17
|
+
)
|
|
18
|
+
from phzyx.auth.errors import (
|
|
19
|
+
AuthError,
|
|
20
|
+
ForbiddenError,
|
|
21
|
+
InvalidCredentialsError,
|
|
22
|
+
LockedError,
|
|
23
|
+
MfaRequiredError,
|
|
24
|
+
UnauthorizedError,
|
|
25
|
+
ValidationAuthError,
|
|
26
|
+
)
|
|
27
|
+
from phzyx.auth.models import (
|
|
28
|
+
AUTH_MODELS,
|
|
29
|
+
AbstractUser,
|
|
30
|
+
Group,
|
|
31
|
+
MFAFactor,
|
|
32
|
+
OAuthAccount,
|
|
33
|
+
Permission,
|
|
34
|
+
User,
|
|
35
|
+
)
|
|
36
|
+
from phzyx.auth.oauth import (
|
|
37
|
+
AuthlibOAuthProvider,
|
|
38
|
+
OAuthNotConfiguredError,
|
|
39
|
+
OAuthProviderConfig,
|
|
40
|
+
StaticOAuthProvider,
|
|
41
|
+
build_provider,
|
|
42
|
+
preset_config,
|
|
43
|
+
)
|
|
44
|
+
from phzyx.auth.orm_stores import (
|
|
45
|
+
HybridUserMap,
|
|
46
|
+
OrmAPIKeyStore,
|
|
47
|
+
OrmPasswordResetStore,
|
|
48
|
+
OrmSessionStore,
|
|
49
|
+
OrmUserRepository,
|
|
50
|
+
)
|
|
51
|
+
from phzyx.auth.passkeys import HmacPasskeyBackend, default_passkey_backend, sign_hmac_assertion
|
|
52
|
+
from phzyx.auth.password import PasswordHasher, generate_token, hash_password, verify_password
|
|
53
|
+
from phzyx.auth.principal import Principal, principal_from_user
|
|
54
|
+
from phzyx.auth.rate_limit import MemoryRateLimiter, RedisRateLimiter
|
|
55
|
+
from phzyx.auth.rbac import has_permission, resolve_permissions, seed_resource_permissions
|
|
56
|
+
from phzyx.auth.service import AuthResult, AuthService, MfaChallenge
|
|
57
|
+
from phzyx.auth.service_async import AsyncAuthService
|
|
58
|
+
from phzyx.auth.sessions import MemorySessionStore
|
|
59
|
+
from phzyx.auth.tokens import JwtService, TokenPair
|
|
60
|
+
|
|
61
|
+
__version__ = "0.1.0"
|
|
62
|
+
|
|
63
|
+
__all__ = [
|
|
64
|
+
"AUTH_MODELS",
|
|
65
|
+
"AbstractUser",
|
|
66
|
+
"AsyncAuthService",
|
|
67
|
+
"AuditLog",
|
|
68
|
+
"AuthConfig",
|
|
69
|
+
"AuthError",
|
|
70
|
+
"AuthResult",
|
|
71
|
+
"AuthService",
|
|
72
|
+
"AuthlibOAuthProvider",
|
|
73
|
+
"ForbiddenError",
|
|
74
|
+
"Group",
|
|
75
|
+
"HmacPasskeyBackend",
|
|
76
|
+
"InvalidCredentialsError",
|
|
77
|
+
"IssuedAPIKey",
|
|
78
|
+
"JwtService",
|
|
79
|
+
"LockedError",
|
|
80
|
+
"HybridUserMap",
|
|
81
|
+
"MFAFactor",
|
|
82
|
+
"MemoryAPIKeyStore",
|
|
83
|
+
"MemoryRateLimiter",
|
|
84
|
+
"MemorySessionStore",
|
|
85
|
+
"MfaChallenge",
|
|
86
|
+
"MfaRequiredError",
|
|
87
|
+
"OAuthAccount",
|
|
88
|
+
"OAuthNotConfiguredError",
|
|
89
|
+
"OAuthProviderConfig",
|
|
90
|
+
"OrmAPIKeyStore",
|
|
91
|
+
"OrmPasswordResetStore",
|
|
92
|
+
"OrmSessionStore",
|
|
93
|
+
"OrmUserRepository",
|
|
94
|
+
"PasswordHasher",
|
|
95
|
+
"Permission",
|
|
96
|
+
"PhzyxAuthz",
|
|
97
|
+
"PhzyxFieldAuthz",
|
|
98
|
+
"Principal",
|
|
99
|
+
"RedisRateLimiter",
|
|
100
|
+
"StaticOAuthProvider",
|
|
101
|
+
"TokenPair",
|
|
102
|
+
"UnauthorizedError",
|
|
103
|
+
"User",
|
|
104
|
+
"ValidationAuthError",
|
|
105
|
+
"__version__",
|
|
106
|
+
"build_provider",
|
|
107
|
+
"create_superuser",
|
|
108
|
+
"default_passkey_backend",
|
|
109
|
+
"generate_token",
|
|
110
|
+
"has_permission",
|
|
111
|
+
"hash_password",
|
|
112
|
+
"mount_auth",
|
|
113
|
+
"mount_auth_litestar",
|
|
114
|
+
"preset_config",
|
|
115
|
+
"principal_from_user",
|
|
116
|
+
"require_auth",
|
|
117
|
+
"require_permissions",
|
|
118
|
+
"require_scopes",
|
|
119
|
+
"require_staff",
|
|
120
|
+
"require_superuser",
|
|
121
|
+
"resolve_permissions",
|
|
122
|
+
"sign_hmac_assertion",
|
|
123
|
+
"seed_resource_permissions",
|
|
124
|
+
"verify_password",
|
|
125
|
+
]
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def __getattr__(name: str) -> Any:
|
|
129
|
+
if name == "mount_auth":
|
|
130
|
+
from phzyx.auth.adapters.fastapi import mount_auth
|
|
131
|
+
|
|
132
|
+
return mount_auth
|
|
133
|
+
if name == "mount_auth_litestar":
|
|
134
|
+
from phzyx.auth.adapters.litestar import mount_auth_litestar
|
|
135
|
+
|
|
136
|
+
return mount_auth_litestar
|
|
137
|
+
if name == "create_superuser":
|
|
138
|
+
from phzyx.auth.cli import create_superuser
|
|
139
|
+
|
|
140
|
+
return create_superuser
|
|
141
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""Framework adapters (FastAPI, Litestar, …)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
__all__ = ["mount_auth", "mount_auth_litestar"]
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def __getattr__(name: str) -> Any:
|
|
11
|
+
if name == "mount_auth":
|
|
12
|
+
from phzyx.auth.adapters.fastapi import mount_auth
|
|
13
|
+
|
|
14
|
+
return mount_auth
|
|
15
|
+
if name == "mount_auth_litestar":
|
|
16
|
+
from phzyx.auth.adapters.litestar import mount_auth_litestar
|
|
17
|
+
|
|
18
|
+
return mount_auth_litestar
|
|
19
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|