pico-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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 David Perez
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,18 @@
1
+ include README.md
2
+ include LICENSE
3
+ include application.yaml
4
+
5
+ recursive-include pico_auth *.py
6
+
7
+ recursive-include tests *.py
8
+
9
+ exclude .gitignore
10
+ exclude Dockerfile*
11
+ exclude docker-compose*.yml
12
+ exclude Makefile
13
+
14
+ prune build
15
+ prune dist
16
+ prune .tox
17
+ prune .pytest_cache
18
+ prune __pycache__
@@ -0,0 +1,246 @@
1
+ Metadata-Version: 2.4
2
+ Name: pico-auth
3
+ Version: 0.1.0
4
+ Summary: Minimal JWT auth server for the pico ecosystem
5
+ Author: David Perez
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/dperezcabrera/pico-auth
8
+ Project-URL: Documentation, https://dperezcabrera.github.io/pico-auth/
9
+ Project-URL: Repository, https://github.com/dperezcabrera/pico-auth
10
+ Project-URL: Issues, https://github.com/dperezcabrera/pico-auth/issues
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Programming Language :: Python :: 3.14
18
+ Classifier: Topic :: Security
19
+ Classifier: Topic :: Internet :: WWW/HTTP
20
+ Requires-Python: >=3.11
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Requires-Dist: pico-ioc>=2.1.0
24
+ Requires-Dist: pico-boot>=0.1.0
25
+ Requires-Dist: pico-fastapi>=0.1.0
26
+ Requires-Dist: pico-sqlalchemy>=0.1.0
27
+ Requires-Dist: pico-client-auth>=0.1.0
28
+ Requires-Dist: python-jose[cryptography]>=3.3
29
+ Requires-Dist: bcrypt>=4.0
30
+ Requires-Dist: aiosqlite>=0.19
31
+ Provides-Extra: dev
32
+ Requires-Dist: pytest>=7.0; extra == "dev"
33
+ Requires-Dist: pytest-asyncio>=0.21; extra == "dev"
34
+ Requires-Dist: httpx>=0.24; extra == "dev"
35
+ Requires-Dist: ruff; extra == "dev"
36
+ Requires-Dist: tox; extra == "dev"
37
+ Provides-Extra: docs
38
+ Requires-Dist: mkdocs-material>=9.0; extra == "docs"
39
+ Requires-Dist: mkdocstrings[python]>=0.24; extra == "docs"
40
+ Requires-Dist: mkdocs-minify-plugin; extra == "docs"
41
+ Requires-Dist: mkdocs-git-revision-date-localized-plugin; extra == "docs"
42
+ Dynamic: license-file
43
+
44
+ # Pico-Auth
45
+
46
+ [![PyPI](https://img.shields.io/pypi/v/pico-auth.svg)](https://pypi.org/project/pico-auth/)
47
+ [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/dperezcabrera/pico-auth)
48
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
49
+ ![CI (tox matrix)](https://github.com/dperezcabrera/pico-auth/actions/workflows/ci.yml/badge.svg)
50
+ [![codecov](https://codecov.io/gh/dperezcabrera/pico-auth/branch/main/graph/badge.svg)](https://codecov.io/gh/dperezcabrera/pico-auth)
51
+ [![Docs](https://img.shields.io/badge/Docs-pico--auth-blue?style=flat&logo=readthedocs&logoColor=white)](https://dperezcabrera.github.io/pico-auth/)
52
+
53
+ **Minimal JWT auth server for the Pico ecosystem.**
54
+
55
+ Pico-Auth is a ready-to-run authentication server built on top of the [pico-framework](https://github.com/dperezcabrera/pico-ioc) stack. It provides:
56
+
57
+ - **RS256 JWT tokens** with auto-generated RSA key pairs
58
+ - **Refresh token rotation** with SHA-256 hashed storage
59
+ - **RBAC** with four built-in roles: `superadmin`, `org_admin`, `operator`, `viewer`
60
+ - **OIDC discovery** endpoints (`.well-known/openid-configuration`, JWKS)
61
+ - **Bcrypt password hashing** (72-byte input limit enforced)
62
+ - **Zero-config startup** with auto-created admin user
63
+
64
+ > Requires Python 3.11+
65
+
66
+ ---
67
+
68
+ ## Architecture
69
+
70
+ Pico-Auth uses the full Pico stack with dependency injection:
71
+
72
+ | Layer | Component | Decorator |
73
+ |-------|-----------|-----------|
74
+ | Config | `AuthSettings` | `@configured(prefix="auth")` |
75
+ | Models | `User`, `RefreshToken` | SQLAlchemy `AppBase` |
76
+ | Repository | `UserRepository`, `RefreshTokenRepository` | `@component` |
77
+ | Service | `AuthService` | `@component` |
78
+ | Security | `JWTProvider`, `PasswordService`, `LocalJWKSProvider` | `@component` |
79
+ | Routes | `AuthController`, `OIDCController` | `@controller` |
80
+
81
+ ---
82
+
83
+ ## Installation
84
+
85
+ ```bash
86
+ pip install -e ".[dev]"
87
+ ```
88
+
89
+ ---
90
+
91
+ ## Quick Start
92
+
93
+ ### 1. Run the Server
94
+
95
+ ```bash
96
+ python -m pico_auth.main
97
+ ```
98
+
99
+ The server starts on `http://localhost:8100` with:
100
+ - An auto-created admin user (`admin@pico.local` / `admin`)
101
+ - SQLite database at `auth.db`
102
+ - RSA keys at `~/.pico-auth/`
103
+
104
+ ### 2. Register a User
105
+
106
+ ```bash
107
+ curl -X POST http://localhost:8100/api/v1/auth/register \
108
+ -H "Content-Type: application/json" \
109
+ -d '{"email": "alice@example.com", "password": "secret123", "display_name": "Alice"}'
110
+ ```
111
+
112
+ ### 3. Login
113
+
114
+ ```bash
115
+ curl -X POST http://localhost:8100/api/v1/auth/login \
116
+ -H "Content-Type: application/json" \
117
+ -d '{"email": "alice@example.com", "password": "secret123"}'
118
+ ```
119
+
120
+ Returns:
121
+ ```json
122
+ {
123
+ "access_token": "eyJhbGciOiJSUzI1NiIs...",
124
+ "refresh_token": "a1b2c3d4...",
125
+ "token_type": "Bearer",
126
+ "expires_in": 900
127
+ }
128
+ ```
129
+
130
+ ### 4. Access Protected Endpoint
131
+
132
+ ```bash
133
+ curl http://localhost:8100/api/v1/auth/me \
134
+ -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..."
135
+ ```
136
+
137
+ ---
138
+
139
+ ## API Endpoints
140
+
141
+ | Method | Path | Auth | Description |
142
+ |--------|------|------|-------------|
143
+ | POST | `/api/v1/auth/register` | No | Register a new user |
144
+ | POST | `/api/v1/auth/login` | No | Login and get tokens |
145
+ | POST | `/api/v1/auth/refresh` | No | Refresh access token |
146
+ | GET | `/api/v1/auth/me` | Bearer | Get current user profile |
147
+ | POST | `/api/v1/auth/me/password` | Bearer | Change password |
148
+ | GET | `/api/v1/auth/users` | Admin | List all users |
149
+ | PUT | `/api/v1/auth/users/{id}/role` | Admin | Update user role |
150
+ | GET | `/api/v1/auth/jwks` | No | JSON Web Key Set |
151
+ | GET | `/.well-known/openid-configuration` | No | OIDC discovery |
152
+
153
+ ---
154
+
155
+ ## Configuration
156
+
157
+ All settings are loaded from `application.yaml` and can be overridden with environment variables:
158
+
159
+ ```yaml
160
+ auth:
161
+ data_dir: "~/.pico-auth" # RSA key storage
162
+ access_token_expire_minutes: 15 # JWT lifetime
163
+ refresh_token_expire_days: 7 # Refresh token lifetime
164
+ issuer: "http://localhost:8100" # JWT issuer claim
165
+ audience: "pico-bot" # JWT audience claim
166
+ auto_create_admin: true # Create admin on startup
167
+ admin_email: "admin@pico.local" # Default admin email
168
+ admin_password: "admin" # Default admin password
169
+
170
+ database:
171
+ url: "sqlite+aiosqlite:///auth.db" # Database URL
172
+ echo: false # SQL logging
173
+
174
+ auth_client:
175
+ enabled: true # Enable auth middleware
176
+ issuer: "http://localhost:8100" # Must match auth.issuer
177
+ audience: "pico-bot" # Must match auth.audience
178
+
179
+ fastapi:
180
+ title: "Pico Auth API"
181
+ version: "0.1.0"
182
+ ```
183
+
184
+ Environment variable override example:
185
+ ```bash
186
+ AUTH_ISSUER=https://auth.myapp.com AUTH_ADMIN_PASSWORD=strong-password python -m pico_auth.main
187
+ ```
188
+
189
+ ---
190
+
191
+ ## JWT Token Claims
192
+
193
+ Access tokens include:
194
+
195
+ | Claim | Description |
196
+ |-------|-------------|
197
+ | `sub` | User ID |
198
+ | `email` | User email |
199
+ | `role` | User role (`superadmin`, `org_admin`, `operator`, `viewer`) |
200
+ | `org_id` | Organization ID |
201
+ | `iss` | Issuer URL |
202
+ | `aud` | Audience |
203
+ | `iat` | Issued at (Unix timestamp) |
204
+ | `exp` | Expiration (Unix timestamp) |
205
+ | `jti` | Unique token ID |
206
+
207
+ ---
208
+
209
+ ## Ecosystem
210
+
211
+ Pico-Auth is built on:
212
+
213
+ | Package | Role |
214
+ |---------|------|
215
+ | [pico-ioc](https://github.com/dperezcabrera/pico-ioc) | Dependency injection container |
216
+ | [pico-boot](https://github.com/dperezcabrera/pico-boot) | Bootstrap and plugin discovery |
217
+ | [pico-fastapi](https://github.com/dperezcabrera/pico-fastapi) | FastAPI integration with `@controller` |
218
+ | [pico-sqlalchemy](https://github.com/dperezcabrera/pico-sqlalchemy) | Async SQLAlchemy with `SessionManager` |
219
+ | [pico-client-auth](https://github.com/dperezcabrera/pico-client-auth) | JWT auth middleware with `SecurityContext` |
220
+
221
+ ---
222
+
223
+ ## Development
224
+
225
+ ```bash
226
+ # Install in dev mode
227
+ pip install -e ".[dev]"
228
+
229
+ # Run tests
230
+ pytest tests/ -v
231
+
232
+ # Run with coverage
233
+ pytest --cov=pico_auth --cov-report=term-missing tests/
234
+
235
+ # Full test matrix
236
+ tox
237
+
238
+ # Lint
239
+ ruff check pico_auth/ tests/
240
+ ```
241
+
242
+ ---
243
+
244
+ ## License
245
+
246
+ MIT - [LICENSE](./LICENSE)
@@ -0,0 +1,203 @@
1
+ # Pico-Auth
2
+
3
+ [![PyPI](https://img.shields.io/pypi/v/pico-auth.svg)](https://pypi.org/project/pico-auth/)
4
+ [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/dperezcabrera/pico-auth)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
6
+ ![CI (tox matrix)](https://github.com/dperezcabrera/pico-auth/actions/workflows/ci.yml/badge.svg)
7
+ [![codecov](https://codecov.io/gh/dperezcabrera/pico-auth/branch/main/graph/badge.svg)](https://codecov.io/gh/dperezcabrera/pico-auth)
8
+ [![Docs](https://img.shields.io/badge/Docs-pico--auth-blue?style=flat&logo=readthedocs&logoColor=white)](https://dperezcabrera.github.io/pico-auth/)
9
+
10
+ **Minimal JWT auth server for the Pico ecosystem.**
11
+
12
+ Pico-Auth is a ready-to-run authentication server built on top of the [pico-framework](https://github.com/dperezcabrera/pico-ioc) stack. It provides:
13
+
14
+ - **RS256 JWT tokens** with auto-generated RSA key pairs
15
+ - **Refresh token rotation** with SHA-256 hashed storage
16
+ - **RBAC** with four built-in roles: `superadmin`, `org_admin`, `operator`, `viewer`
17
+ - **OIDC discovery** endpoints (`.well-known/openid-configuration`, JWKS)
18
+ - **Bcrypt password hashing** (72-byte input limit enforced)
19
+ - **Zero-config startup** with auto-created admin user
20
+
21
+ > Requires Python 3.11+
22
+
23
+ ---
24
+
25
+ ## Architecture
26
+
27
+ Pico-Auth uses the full Pico stack with dependency injection:
28
+
29
+ | Layer | Component | Decorator |
30
+ |-------|-----------|-----------|
31
+ | Config | `AuthSettings` | `@configured(prefix="auth")` |
32
+ | Models | `User`, `RefreshToken` | SQLAlchemy `AppBase` |
33
+ | Repository | `UserRepository`, `RefreshTokenRepository` | `@component` |
34
+ | Service | `AuthService` | `@component` |
35
+ | Security | `JWTProvider`, `PasswordService`, `LocalJWKSProvider` | `@component` |
36
+ | Routes | `AuthController`, `OIDCController` | `@controller` |
37
+
38
+ ---
39
+
40
+ ## Installation
41
+
42
+ ```bash
43
+ pip install -e ".[dev]"
44
+ ```
45
+
46
+ ---
47
+
48
+ ## Quick Start
49
+
50
+ ### 1. Run the Server
51
+
52
+ ```bash
53
+ python -m pico_auth.main
54
+ ```
55
+
56
+ The server starts on `http://localhost:8100` with:
57
+ - An auto-created admin user (`admin@pico.local` / `admin`)
58
+ - SQLite database at `auth.db`
59
+ - RSA keys at `~/.pico-auth/`
60
+
61
+ ### 2. Register a User
62
+
63
+ ```bash
64
+ curl -X POST http://localhost:8100/api/v1/auth/register \
65
+ -H "Content-Type: application/json" \
66
+ -d '{"email": "alice@example.com", "password": "secret123", "display_name": "Alice"}'
67
+ ```
68
+
69
+ ### 3. Login
70
+
71
+ ```bash
72
+ curl -X POST http://localhost:8100/api/v1/auth/login \
73
+ -H "Content-Type: application/json" \
74
+ -d '{"email": "alice@example.com", "password": "secret123"}'
75
+ ```
76
+
77
+ Returns:
78
+ ```json
79
+ {
80
+ "access_token": "eyJhbGciOiJSUzI1NiIs...",
81
+ "refresh_token": "a1b2c3d4...",
82
+ "token_type": "Bearer",
83
+ "expires_in": 900
84
+ }
85
+ ```
86
+
87
+ ### 4. Access Protected Endpoint
88
+
89
+ ```bash
90
+ curl http://localhost:8100/api/v1/auth/me \
91
+ -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..."
92
+ ```
93
+
94
+ ---
95
+
96
+ ## API Endpoints
97
+
98
+ | Method | Path | Auth | Description |
99
+ |--------|------|------|-------------|
100
+ | POST | `/api/v1/auth/register` | No | Register a new user |
101
+ | POST | `/api/v1/auth/login` | No | Login and get tokens |
102
+ | POST | `/api/v1/auth/refresh` | No | Refresh access token |
103
+ | GET | `/api/v1/auth/me` | Bearer | Get current user profile |
104
+ | POST | `/api/v1/auth/me/password` | Bearer | Change password |
105
+ | GET | `/api/v1/auth/users` | Admin | List all users |
106
+ | PUT | `/api/v1/auth/users/{id}/role` | Admin | Update user role |
107
+ | GET | `/api/v1/auth/jwks` | No | JSON Web Key Set |
108
+ | GET | `/.well-known/openid-configuration` | No | OIDC discovery |
109
+
110
+ ---
111
+
112
+ ## Configuration
113
+
114
+ All settings are loaded from `application.yaml` and can be overridden with environment variables:
115
+
116
+ ```yaml
117
+ auth:
118
+ data_dir: "~/.pico-auth" # RSA key storage
119
+ access_token_expire_minutes: 15 # JWT lifetime
120
+ refresh_token_expire_days: 7 # Refresh token lifetime
121
+ issuer: "http://localhost:8100" # JWT issuer claim
122
+ audience: "pico-bot" # JWT audience claim
123
+ auto_create_admin: true # Create admin on startup
124
+ admin_email: "admin@pico.local" # Default admin email
125
+ admin_password: "admin" # Default admin password
126
+
127
+ database:
128
+ url: "sqlite+aiosqlite:///auth.db" # Database URL
129
+ echo: false # SQL logging
130
+
131
+ auth_client:
132
+ enabled: true # Enable auth middleware
133
+ issuer: "http://localhost:8100" # Must match auth.issuer
134
+ audience: "pico-bot" # Must match auth.audience
135
+
136
+ fastapi:
137
+ title: "Pico Auth API"
138
+ version: "0.1.0"
139
+ ```
140
+
141
+ Environment variable override example:
142
+ ```bash
143
+ AUTH_ISSUER=https://auth.myapp.com AUTH_ADMIN_PASSWORD=strong-password python -m pico_auth.main
144
+ ```
145
+
146
+ ---
147
+
148
+ ## JWT Token Claims
149
+
150
+ Access tokens include:
151
+
152
+ | Claim | Description |
153
+ |-------|-------------|
154
+ | `sub` | User ID |
155
+ | `email` | User email |
156
+ | `role` | User role (`superadmin`, `org_admin`, `operator`, `viewer`) |
157
+ | `org_id` | Organization ID |
158
+ | `iss` | Issuer URL |
159
+ | `aud` | Audience |
160
+ | `iat` | Issued at (Unix timestamp) |
161
+ | `exp` | Expiration (Unix timestamp) |
162
+ | `jti` | Unique token ID |
163
+
164
+ ---
165
+
166
+ ## Ecosystem
167
+
168
+ Pico-Auth is built on:
169
+
170
+ | Package | Role |
171
+ |---------|------|
172
+ | [pico-ioc](https://github.com/dperezcabrera/pico-ioc) | Dependency injection container |
173
+ | [pico-boot](https://github.com/dperezcabrera/pico-boot) | Bootstrap and plugin discovery |
174
+ | [pico-fastapi](https://github.com/dperezcabrera/pico-fastapi) | FastAPI integration with `@controller` |
175
+ | [pico-sqlalchemy](https://github.com/dperezcabrera/pico-sqlalchemy) | Async SQLAlchemy with `SessionManager` |
176
+ | [pico-client-auth](https://github.com/dperezcabrera/pico-client-auth) | JWT auth middleware with `SecurityContext` |
177
+
178
+ ---
179
+
180
+ ## Development
181
+
182
+ ```bash
183
+ # Install in dev mode
184
+ pip install -e ".[dev]"
185
+
186
+ # Run tests
187
+ pytest tests/ -v
188
+
189
+ # Run with coverage
190
+ pytest --cov=pico_auth --cov-report=term-missing tests/
191
+
192
+ # Full test matrix
193
+ tox
194
+
195
+ # Lint
196
+ ruff check pico_auth/ tests/
197
+ ```
198
+
199
+ ---
200
+
201
+ ## License
202
+
203
+ MIT - [LICENSE](./LICENSE)
@@ -0,0 +1,22 @@
1
+ auth:
2
+ data_dir: "~/.pico-auth"
3
+ access_token_expire_minutes: 15
4
+ refresh_token_expire_days: 7
5
+ issuer: "http://localhost:8100"
6
+ audience: "pico-bot"
7
+ auto_create_admin: true
8
+ admin_email: "admin@pico.local"
9
+ admin_password: "admin"
10
+
11
+ database:
12
+ url: "sqlite+aiosqlite:///auth.db"
13
+ echo: false
14
+
15
+ auth_client:
16
+ enabled: true
17
+ issuer: "http://localhost:8100"
18
+ audience: "pico-bot"
19
+
20
+ fastapi:
21
+ title: "Pico Auth API"
22
+ version: "0.1.0"
@@ -0,0 +1,29 @@
1
+ """pico-auth -- minimal JWT auth server for the pico ecosystem."""
2
+
3
+ import pico_auth.local_auth_configurer as local_auth_configurer # noqa: F401 — patches AuthFastapiConfigurer
4
+ from pico_auth.config import AuthSettings
5
+ from pico_auth.errors import AuthError
6
+ from pico_auth.jwt_provider import JWTProvider
7
+ from pico_auth.local_jwks_provider import LocalJWKSProvider
8
+ from pico_auth.models import RefreshToken, User
9
+ from pico_auth.passwords import PasswordService
10
+ from pico_auth.repository import RefreshTokenRepository, UserRepository
11
+ from pico_auth.routes import AuthController, OIDCController
12
+ from pico_auth.schema import create_tables
13
+ from pico_auth.service import AuthService
14
+
15
+ __all__ = [
16
+ "AuthController",
17
+ "AuthError",
18
+ "AuthSettings",
19
+ "AuthService",
20
+ "JWTProvider",
21
+ "LocalJWKSProvider",
22
+ "OIDCController",
23
+ "PasswordService",
24
+ "RefreshToken",
25
+ "RefreshTokenRepository",
26
+ "User",
27
+ "UserRepository",
28
+ "create_tables",
29
+ ]
@@ -0,0 +1,33 @@
1
+ """Auth server configuration using pico-ioc @configured."""
2
+
3
+ from dataclasses import dataclass
4
+ from pathlib import Path
5
+
6
+ from pico_ioc import configured
7
+
8
+
9
+ @configured(target="self", prefix="auth", mapping="tree")
10
+ @dataclass
11
+ class AuthSettings:
12
+ """Auth server settings from application.yaml / env vars."""
13
+
14
+ data_dir: str = "~/.pico-auth"
15
+ access_token_expire_minutes: int = 15
16
+ refresh_token_expire_days: int = 7
17
+ issuer: str = "http://localhost:8100"
18
+ audience: str = "pico-bot"
19
+ auto_create_admin: bool = True
20
+ admin_email: str = "admin@pico.local"
21
+ admin_password: str = "admin"
22
+
23
+ @property
24
+ def data_path(self) -> Path:
25
+ return Path(self.data_dir).expanduser()
26
+
27
+ @property
28
+ def private_key_path(self) -> Path:
29
+ return self.data_path / "private.pem"
30
+
31
+ @property
32
+ def public_key_path(self) -> Path:
33
+ return self.data_path / "public.pem"
@@ -0,0 +1,42 @@
1
+ """Auth error hierarchy."""
2
+
3
+
4
+ class AuthError(Exception):
5
+ def __init__(self, message: str):
6
+ self.message = message
7
+ super().__init__(message)
8
+
9
+
10
+ class UserExistsError(AuthError):
11
+ def __init__(self, email: str):
12
+ super().__init__(f"User already exists: {email}")
13
+
14
+
15
+ class InvalidCredentialsError(AuthError):
16
+ def __init__(self):
17
+ super().__init__("Invalid email or password")
18
+
19
+
20
+ class TokenExpiredError(AuthError):
21
+ def __init__(self):
22
+ super().__init__("Token has expired")
23
+
24
+
25
+ class TokenInvalidError(AuthError):
26
+ def __init__(self):
27
+ super().__init__("Invalid token")
28
+
29
+
30
+ class UserNotFoundError(AuthError):
31
+ def __init__(self, user_id: str):
32
+ super().__init__(f"User not found: {user_id}")
33
+
34
+
35
+ class InsufficientPermissionsError(AuthError):
36
+ def __init__(self):
37
+ super().__init__("Insufficient permissions")
38
+
39
+
40
+ class UserSuspendedError(AuthError):
41
+ def __init__(self):
42
+ super().__init__("User account is suspended")