auth-kit-fastapi 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.
- auth_kit_fastapi-0.1.0/PKG-INFO +226 -0
- auth_kit_fastapi-0.1.0/README.md +171 -0
- auth_kit_fastapi-0.1.0/auth_kit_fastapi/__init__.py +27 -0
- auth_kit_fastapi-0.1.0/auth_kit_fastapi/schemas/__init__.py +84 -0
- auth_kit_fastapi-0.1.0/auth_kit_fastapi/schemas/auth.py +145 -0
- auth_kit_fastapi-0.1.0/auth_kit_fastapi/schemas/passkey.py +129 -0
- auth_kit_fastapi-0.1.0/auth_kit_fastapi/schemas/two_factor.py +73 -0
- auth_kit_fastapi-0.1.0/auth_kit_fastapi/services/__init__.py +17 -0
- auth_kit_fastapi-0.1.0/auth_kit_fastapi/services/email_service.py +468 -0
- auth_kit_fastapi-0.1.0/auth_kit_fastapi/services/passkey_service.py +461 -0
- auth_kit_fastapi-0.1.0/auth_kit_fastapi/services/two_factor_service.py +422 -0
- auth_kit_fastapi-0.1.0/auth_kit_fastapi/services/user_service.py +407 -0
- auth_kit_fastapi-0.1.0/auth_kit_fastapi.egg-info/PKG-INFO +226 -0
- auth_kit_fastapi-0.1.0/auth_kit_fastapi.egg-info/SOURCES.txt +23 -0
- auth_kit_fastapi-0.1.0/auth_kit_fastapi.egg-info/dependency_links.txt +1 -0
- auth_kit_fastapi-0.1.0/auth_kit_fastapi.egg-info/requires.txt +29 -0
- auth_kit_fastapi-0.1.0/auth_kit_fastapi.egg-info/top_level.txt +2 -0
- auth_kit_fastapi-0.1.0/setup.cfg +4 -0
- auth_kit_fastapi-0.1.0/setup.py +56 -0
- auth_kit_fastapi-0.1.0/tests/__init__.py +1 -0
- auth_kit_fastapi-0.1.0/tests/conftest.py +198 -0
- auth_kit_fastapi-0.1.0/tests/test_auth_endpoints.py +350 -0
- auth_kit_fastapi-0.1.0/tests/test_passkey_endpoints.py +282 -0
- auth_kit_fastapi-0.1.0/tests/test_services.py +449 -0
- auth_kit_fastapi-0.1.0/tests/test_two_factor_endpoints.py +377 -0
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: auth-kit-fastapi
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: FastAPI authentication backend for Auth Kit
|
|
5
|
+
Home-page: https://github.com/erickva/auth-kit
|
|
6
|
+
Author: Erick Ama
|
|
7
|
+
Author-email: me@erick.no
|
|
8
|
+
Classifier: Development Status :: 4 - Beta
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Framework :: FastAPI
|
|
18
|
+
Requires-Python: >=3.8
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
Requires-Dist: fastapi>=0.100.0
|
|
21
|
+
Requires-Dist: sqlalchemy>=2.0.0
|
|
22
|
+
Requires-Dist: pydantic>=2.0.0
|
|
23
|
+
Requires-Dist: pydantic-settings>=2.0.0
|
|
24
|
+
Requires-Dist: python-jose[cryptography]>=3.3.0
|
|
25
|
+
Requires-Dist: passlib[bcrypt]>=1.7.4
|
|
26
|
+
Requires-Dist: python-multipart>=0.0.6
|
|
27
|
+
Requires-Dist: email-validator>=2.0.0
|
|
28
|
+
Requires-Dist: pyotp>=2.9.0
|
|
29
|
+
Requires-Dist: qrcode>=7.4.0
|
|
30
|
+
Requires-Dist: webauthn>=1.9.0
|
|
31
|
+
Requires-Dist: alembic>=1.12.0
|
|
32
|
+
Provides-Extra: dev
|
|
33
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
34
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
|
|
35
|
+
Requires-Dist: httpx>=0.24.0; extra == "dev"
|
|
36
|
+
Requires-Dist: black>=23.0.0; extra == "dev"
|
|
37
|
+
Requires-Dist: flake8>=6.0.0; extra == "dev"
|
|
38
|
+
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
39
|
+
Provides-Extra: redis
|
|
40
|
+
Requires-Dist: redis>=4.5.0; extra == "redis"
|
|
41
|
+
Provides-Extra: postgres
|
|
42
|
+
Requires-Dist: psycopg2-binary>=2.9.0; extra == "postgres"
|
|
43
|
+
Provides-Extra: mysql
|
|
44
|
+
Requires-Dist: pymysql>=1.1.0; extra == "mysql"
|
|
45
|
+
Dynamic: author
|
|
46
|
+
Dynamic: author-email
|
|
47
|
+
Dynamic: classifier
|
|
48
|
+
Dynamic: description
|
|
49
|
+
Dynamic: description-content-type
|
|
50
|
+
Dynamic: home-page
|
|
51
|
+
Dynamic: provides-extra
|
|
52
|
+
Dynamic: requires-dist
|
|
53
|
+
Dynamic: requires-python
|
|
54
|
+
Dynamic: summary
|
|
55
|
+
|
|
56
|
+
# Auth Kit FastAPI
|
|
57
|
+
|
|
58
|
+
FastAPI authentication backend for Auth Kit. Provides a complete authentication solution with JWT tokens, passkeys, 2FA, and more.
|
|
59
|
+
|
|
60
|
+
## Installation
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
pip install auth-kit-fastapi
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Quick Start
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
from fastapi import FastAPI
|
|
70
|
+
from auth_kit_fastapi import create_auth_app, AuthConfig
|
|
71
|
+
|
|
72
|
+
app = FastAPI()
|
|
73
|
+
|
|
74
|
+
# Configure authentication
|
|
75
|
+
auth_config = AuthConfig(
|
|
76
|
+
database_url="postgresql://localhost/myapp",
|
|
77
|
+
jwt_secret="your-secret-key",
|
|
78
|
+
features={
|
|
79
|
+
"passkeys": True,
|
|
80
|
+
"two_factor": True,
|
|
81
|
+
"email_verification": True
|
|
82
|
+
}
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
# Create auth app
|
|
86
|
+
auth_app = create_auth_app(auth_config)
|
|
87
|
+
|
|
88
|
+
# Mount auth routes
|
|
89
|
+
app.mount("/api/auth", auth_app)
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Features
|
|
93
|
+
|
|
94
|
+
- 🔐 JWT-based authentication with refresh tokens
|
|
95
|
+
- 🔑 WebAuthn/Passkey support
|
|
96
|
+
- 🔒 Two-factor authentication (TOTP)
|
|
97
|
+
- 📧 Email verification
|
|
98
|
+
- 🔄 Password reset flow
|
|
99
|
+
- 👤 User management
|
|
100
|
+
- 🗄️ SQLAlchemy ORM support
|
|
101
|
+
- 🔍 Extensible user model
|
|
102
|
+
- 🛡️ Security best practices
|
|
103
|
+
|
|
104
|
+
## Configuration
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
from auth_kit_fastapi import AuthConfig
|
|
108
|
+
|
|
109
|
+
config = AuthConfig(
|
|
110
|
+
# Database
|
|
111
|
+
database_url="postgresql://user:pass@localhost/db",
|
|
112
|
+
|
|
113
|
+
# JWT Settings
|
|
114
|
+
jwt_secret="your-secret-key",
|
|
115
|
+
jwt_algorithm="HS256",
|
|
116
|
+
access_token_expire_minutes=30,
|
|
117
|
+
refresh_token_expire_days=7,
|
|
118
|
+
|
|
119
|
+
# Passkey Settings
|
|
120
|
+
passkey_rp_id="localhost",
|
|
121
|
+
passkey_rp_name="My App",
|
|
122
|
+
passkey_origin="http://localhost:3000",
|
|
123
|
+
|
|
124
|
+
# Email Settings
|
|
125
|
+
email_from="noreply@example.com",
|
|
126
|
+
email_from_name="My App",
|
|
127
|
+
|
|
128
|
+
# Features
|
|
129
|
+
features={
|
|
130
|
+
"passkeys": True,
|
|
131
|
+
"two_factor": True,
|
|
132
|
+
"email_verification": True,
|
|
133
|
+
"social_login": ["google", "github"]
|
|
134
|
+
}
|
|
135
|
+
)
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Custom User Model
|
|
139
|
+
|
|
140
|
+
Extend the base User model with your own fields:
|
|
141
|
+
|
|
142
|
+
```python
|
|
143
|
+
from auth_kit_fastapi import BaseUser
|
|
144
|
+
from sqlalchemy import Column, String
|
|
145
|
+
|
|
146
|
+
class User(BaseUser):
|
|
147
|
+
__tablename__ = "users"
|
|
148
|
+
|
|
149
|
+
# Add custom fields
|
|
150
|
+
company_name = Column(String, nullable=True)
|
|
151
|
+
department = Column(String, nullable=True)
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## API Endpoints
|
|
155
|
+
|
|
156
|
+
All endpoints are mounted under your chosen prefix (e.g., `/api/auth`):
|
|
157
|
+
|
|
158
|
+
### Authentication
|
|
159
|
+
- `POST /register` - Register new user
|
|
160
|
+
- `POST /login` - Login with email/password
|
|
161
|
+
- `POST /logout` - Logout user
|
|
162
|
+
- `POST /refresh` - Refresh access token
|
|
163
|
+
- `GET /me` - Get current user
|
|
164
|
+
|
|
165
|
+
### Password Management
|
|
166
|
+
- `POST /password/change` - Change password
|
|
167
|
+
- `POST /password/reset` - Request password reset
|
|
168
|
+
- `POST /password/reset/confirm` - Confirm password reset
|
|
169
|
+
|
|
170
|
+
### Email Verification
|
|
171
|
+
- `GET /verify-email/{token}` - Verify email
|
|
172
|
+
- `POST /resend-verification` - Resend verification email
|
|
173
|
+
|
|
174
|
+
### Passkeys
|
|
175
|
+
- `GET /passkeys` - List user's passkeys
|
|
176
|
+
- `POST /passkeys/register/begin` - Begin passkey registration
|
|
177
|
+
- `POST /passkeys/register/complete` - Complete passkey registration
|
|
178
|
+
- `POST /passkeys/authenticate/begin` - Begin passkey authentication
|
|
179
|
+
- `POST /passkeys/authenticate/complete` - Complete passkey authentication
|
|
180
|
+
- `DELETE /passkeys/{id}` - Delete passkey
|
|
181
|
+
|
|
182
|
+
### Two-Factor Authentication
|
|
183
|
+
- `POST /2fa/setup/begin` - Begin 2FA setup
|
|
184
|
+
- `POST /2fa/setup/verify` - Verify and enable 2FA
|
|
185
|
+
- `POST /2fa/disable` - Disable 2FA
|
|
186
|
+
- `POST /2fa/verify/login` - Verify 2FA during login
|
|
187
|
+
- `POST /2fa/recovery-codes` - Regenerate recovery codes
|
|
188
|
+
|
|
189
|
+
## Middleware & Dependencies
|
|
190
|
+
|
|
191
|
+
Use the provided dependencies to protect your routes:
|
|
192
|
+
|
|
193
|
+
```python
|
|
194
|
+
from fastapi import Depends
|
|
195
|
+
from auth_kit_fastapi import get_current_user, require_verified_user
|
|
196
|
+
|
|
197
|
+
@app.get("/protected")
|
|
198
|
+
async def protected_route(user = Depends(get_current_user)):
|
|
199
|
+
return {"message": f"Hello {user.email}"}
|
|
200
|
+
|
|
201
|
+
@app.get("/verified-only")
|
|
202
|
+
async def verified_only(user = Depends(require_verified_user)):
|
|
203
|
+
return {"message": "Only verified users can see this"}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## Events & Hooks
|
|
207
|
+
|
|
208
|
+
Subscribe to authentication events:
|
|
209
|
+
|
|
210
|
+
```python
|
|
211
|
+
from auth_kit_fastapi import auth_events
|
|
212
|
+
|
|
213
|
+
@auth_events.on("user_registered")
|
|
214
|
+
async def on_user_registered(user):
|
|
215
|
+
# Send welcome email
|
|
216
|
+
print(f"New user registered: {user.email}")
|
|
217
|
+
|
|
218
|
+
@auth_events.on("user_logged_in")
|
|
219
|
+
async def on_user_logged_in(user):
|
|
220
|
+
# Log login event
|
|
221
|
+
print(f"User logged in: {user.email}")
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
## License
|
|
225
|
+
|
|
226
|
+
MIT License
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# Auth Kit FastAPI
|
|
2
|
+
|
|
3
|
+
FastAPI authentication backend for Auth Kit. Provides a complete authentication solution with JWT tokens, passkeys, 2FA, and more.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install auth-kit-fastapi
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
from fastapi import FastAPI
|
|
15
|
+
from auth_kit_fastapi import create_auth_app, AuthConfig
|
|
16
|
+
|
|
17
|
+
app = FastAPI()
|
|
18
|
+
|
|
19
|
+
# Configure authentication
|
|
20
|
+
auth_config = AuthConfig(
|
|
21
|
+
database_url="postgresql://localhost/myapp",
|
|
22
|
+
jwt_secret="your-secret-key",
|
|
23
|
+
features={
|
|
24
|
+
"passkeys": True,
|
|
25
|
+
"two_factor": True,
|
|
26
|
+
"email_verification": True
|
|
27
|
+
}
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
# Create auth app
|
|
31
|
+
auth_app = create_auth_app(auth_config)
|
|
32
|
+
|
|
33
|
+
# Mount auth routes
|
|
34
|
+
app.mount("/api/auth", auth_app)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Features
|
|
38
|
+
|
|
39
|
+
- 🔐 JWT-based authentication with refresh tokens
|
|
40
|
+
- 🔑 WebAuthn/Passkey support
|
|
41
|
+
- 🔒 Two-factor authentication (TOTP)
|
|
42
|
+
- 📧 Email verification
|
|
43
|
+
- 🔄 Password reset flow
|
|
44
|
+
- 👤 User management
|
|
45
|
+
- 🗄️ SQLAlchemy ORM support
|
|
46
|
+
- 🔍 Extensible user model
|
|
47
|
+
- 🛡️ Security best practices
|
|
48
|
+
|
|
49
|
+
## Configuration
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
from auth_kit_fastapi import AuthConfig
|
|
53
|
+
|
|
54
|
+
config = AuthConfig(
|
|
55
|
+
# Database
|
|
56
|
+
database_url="postgresql://user:pass@localhost/db",
|
|
57
|
+
|
|
58
|
+
# JWT Settings
|
|
59
|
+
jwt_secret="your-secret-key",
|
|
60
|
+
jwt_algorithm="HS256",
|
|
61
|
+
access_token_expire_minutes=30,
|
|
62
|
+
refresh_token_expire_days=7,
|
|
63
|
+
|
|
64
|
+
# Passkey Settings
|
|
65
|
+
passkey_rp_id="localhost",
|
|
66
|
+
passkey_rp_name="My App",
|
|
67
|
+
passkey_origin="http://localhost:3000",
|
|
68
|
+
|
|
69
|
+
# Email Settings
|
|
70
|
+
email_from="noreply@example.com",
|
|
71
|
+
email_from_name="My App",
|
|
72
|
+
|
|
73
|
+
# Features
|
|
74
|
+
features={
|
|
75
|
+
"passkeys": True,
|
|
76
|
+
"two_factor": True,
|
|
77
|
+
"email_verification": True,
|
|
78
|
+
"social_login": ["google", "github"]
|
|
79
|
+
}
|
|
80
|
+
)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Custom User Model
|
|
84
|
+
|
|
85
|
+
Extend the base User model with your own fields:
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
from auth_kit_fastapi import BaseUser
|
|
89
|
+
from sqlalchemy import Column, String
|
|
90
|
+
|
|
91
|
+
class User(BaseUser):
|
|
92
|
+
__tablename__ = "users"
|
|
93
|
+
|
|
94
|
+
# Add custom fields
|
|
95
|
+
company_name = Column(String, nullable=True)
|
|
96
|
+
department = Column(String, nullable=True)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## API Endpoints
|
|
100
|
+
|
|
101
|
+
All endpoints are mounted under your chosen prefix (e.g., `/api/auth`):
|
|
102
|
+
|
|
103
|
+
### Authentication
|
|
104
|
+
- `POST /register` - Register new user
|
|
105
|
+
- `POST /login` - Login with email/password
|
|
106
|
+
- `POST /logout` - Logout user
|
|
107
|
+
- `POST /refresh` - Refresh access token
|
|
108
|
+
- `GET /me` - Get current user
|
|
109
|
+
|
|
110
|
+
### Password Management
|
|
111
|
+
- `POST /password/change` - Change password
|
|
112
|
+
- `POST /password/reset` - Request password reset
|
|
113
|
+
- `POST /password/reset/confirm` - Confirm password reset
|
|
114
|
+
|
|
115
|
+
### Email Verification
|
|
116
|
+
- `GET /verify-email/{token}` - Verify email
|
|
117
|
+
- `POST /resend-verification` - Resend verification email
|
|
118
|
+
|
|
119
|
+
### Passkeys
|
|
120
|
+
- `GET /passkeys` - List user's passkeys
|
|
121
|
+
- `POST /passkeys/register/begin` - Begin passkey registration
|
|
122
|
+
- `POST /passkeys/register/complete` - Complete passkey registration
|
|
123
|
+
- `POST /passkeys/authenticate/begin` - Begin passkey authentication
|
|
124
|
+
- `POST /passkeys/authenticate/complete` - Complete passkey authentication
|
|
125
|
+
- `DELETE /passkeys/{id}` - Delete passkey
|
|
126
|
+
|
|
127
|
+
### Two-Factor Authentication
|
|
128
|
+
- `POST /2fa/setup/begin` - Begin 2FA setup
|
|
129
|
+
- `POST /2fa/setup/verify` - Verify and enable 2FA
|
|
130
|
+
- `POST /2fa/disable` - Disable 2FA
|
|
131
|
+
- `POST /2fa/verify/login` - Verify 2FA during login
|
|
132
|
+
- `POST /2fa/recovery-codes` - Regenerate recovery codes
|
|
133
|
+
|
|
134
|
+
## Middleware & Dependencies
|
|
135
|
+
|
|
136
|
+
Use the provided dependencies to protect your routes:
|
|
137
|
+
|
|
138
|
+
```python
|
|
139
|
+
from fastapi import Depends
|
|
140
|
+
from auth_kit_fastapi import get_current_user, require_verified_user
|
|
141
|
+
|
|
142
|
+
@app.get("/protected")
|
|
143
|
+
async def protected_route(user = Depends(get_current_user)):
|
|
144
|
+
return {"message": f"Hello {user.email}"}
|
|
145
|
+
|
|
146
|
+
@app.get("/verified-only")
|
|
147
|
+
async def verified_only(user = Depends(require_verified_user)):
|
|
148
|
+
return {"message": "Only verified users can see this"}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Events & Hooks
|
|
152
|
+
|
|
153
|
+
Subscribe to authentication events:
|
|
154
|
+
|
|
155
|
+
```python
|
|
156
|
+
from auth_kit_fastapi import auth_events
|
|
157
|
+
|
|
158
|
+
@auth_events.on("user_registered")
|
|
159
|
+
async def on_user_registered(user):
|
|
160
|
+
# Send welcome email
|
|
161
|
+
print(f"New user registered: {user.email}")
|
|
162
|
+
|
|
163
|
+
@auth_events.on("user_logged_in")
|
|
164
|
+
async def on_user_logged_in(user):
|
|
165
|
+
# Log login event
|
|
166
|
+
print(f"User logged in: {user.email}")
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## License
|
|
170
|
+
|
|
171
|
+
MIT License
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Auth Kit FastAPI - Complete authentication solution for FastAPI applications
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from .core.config import AuthConfig
|
|
6
|
+
from .core.app import create_auth_app
|
|
7
|
+
from .core.dependencies import (
|
|
8
|
+
get_current_user,
|
|
9
|
+
get_current_active_user,
|
|
10
|
+
require_verified_user,
|
|
11
|
+
require_superuser
|
|
12
|
+
)
|
|
13
|
+
from .models.user import BaseUser
|
|
14
|
+
from .core.events import auth_events
|
|
15
|
+
|
|
16
|
+
__version__ = "1.0.0"
|
|
17
|
+
|
|
18
|
+
__all__ = [
|
|
19
|
+
"AuthConfig",
|
|
20
|
+
"create_auth_app",
|
|
21
|
+
"get_current_user",
|
|
22
|
+
"get_current_active_user",
|
|
23
|
+
"require_verified_user",
|
|
24
|
+
"require_superuser",
|
|
25
|
+
"BaseUser",
|
|
26
|
+
"auth_events"
|
|
27
|
+
]
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Export all schemas
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from .auth import (
|
|
6
|
+
UserBase,
|
|
7
|
+
UserCreate,
|
|
8
|
+
UserUpdate,
|
|
9
|
+
UserResponse,
|
|
10
|
+
LoginRequest,
|
|
11
|
+
TokenResponse,
|
|
12
|
+
LoginResponse,
|
|
13
|
+
RefreshTokenRequest,
|
|
14
|
+
LogoutRequest,
|
|
15
|
+
PasswordChangeRequest,
|
|
16
|
+
PasswordResetRequest,
|
|
17
|
+
PasswordResetConfirmRequest,
|
|
18
|
+
EmailVerificationRequest,
|
|
19
|
+
MessageResponse,
|
|
20
|
+
ErrorResponse
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
from .passkey import (
|
|
24
|
+
PasskeyBase,
|
|
25
|
+
PasskeyCreate,
|
|
26
|
+
PasskeyResponse,
|
|
27
|
+
PasskeyListResponse,
|
|
28
|
+
RegistrationOptionsResponse,
|
|
29
|
+
RegistrationCompleteRequest,
|
|
30
|
+
AuthenticationOptionsResponse,
|
|
31
|
+
AuthenticationCompleteRequest,
|
|
32
|
+
AuthenticationBeginRequest
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
from .two_factor import (
|
|
36
|
+
TwoFactorSetupResponse,
|
|
37
|
+
TwoFactorVerifyRequest,
|
|
38
|
+
TwoFactorEnableResponse,
|
|
39
|
+
TwoFactorDisableRequest,
|
|
40
|
+
RecoveryCodesRegenerateRequest,
|
|
41
|
+
RecoveryCodesResponse,
|
|
42
|
+
TwoFactorLoginVerifyRequest,
|
|
43
|
+
TwoFactorStatusResponse
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
__all__ = [
|
|
47
|
+
# Auth schemas
|
|
48
|
+
"UserBase",
|
|
49
|
+
"UserCreate",
|
|
50
|
+
"UserUpdate",
|
|
51
|
+
"UserResponse",
|
|
52
|
+
"LoginRequest",
|
|
53
|
+
"TokenResponse",
|
|
54
|
+
"LoginResponse",
|
|
55
|
+
"RefreshTokenRequest",
|
|
56
|
+
"LogoutRequest",
|
|
57
|
+
"PasswordChangeRequest",
|
|
58
|
+
"PasswordResetRequest",
|
|
59
|
+
"PasswordResetConfirmRequest",
|
|
60
|
+
"EmailVerificationRequest",
|
|
61
|
+
"MessageResponse",
|
|
62
|
+
"ErrorResponse",
|
|
63
|
+
|
|
64
|
+
# Passkey schemas
|
|
65
|
+
"PasskeyBase",
|
|
66
|
+
"PasskeyCreate",
|
|
67
|
+
"PasskeyResponse",
|
|
68
|
+
"PasskeyListResponse",
|
|
69
|
+
"RegistrationOptionsResponse",
|
|
70
|
+
"RegistrationCompleteRequest",
|
|
71
|
+
"AuthenticationOptionsResponse",
|
|
72
|
+
"AuthenticationCompleteRequest",
|
|
73
|
+
"AuthenticationBeginRequest",
|
|
74
|
+
|
|
75
|
+
# 2FA schemas
|
|
76
|
+
"TwoFactorSetupResponse",
|
|
77
|
+
"TwoFactorVerifyRequest",
|
|
78
|
+
"TwoFactorEnableResponse",
|
|
79
|
+
"TwoFactorDisableRequest",
|
|
80
|
+
"RecoveryCodesRegenerateRequest",
|
|
81
|
+
"RecoveryCodesResponse",
|
|
82
|
+
"TwoFactorLoginVerifyRequest",
|
|
83
|
+
"TwoFactorStatusResponse"
|
|
84
|
+
]
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Authentication schemas for request/response validation
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from datetime import datetime
|
|
6
|
+
from typing import Optional, Dict, Any
|
|
7
|
+
from uuid import UUID
|
|
8
|
+
from pydantic import BaseModel, EmailStr, Field, validator
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
# Base schemas
|
|
12
|
+
class UserBase(BaseModel):
|
|
13
|
+
"""Base user schema"""
|
|
14
|
+
email: EmailStr
|
|
15
|
+
first_name: Optional[str] = None
|
|
16
|
+
last_name: Optional[str] = None
|
|
17
|
+
phone_number: Optional[str] = None
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class UserCreate(UserBase):
|
|
21
|
+
"""User registration schema"""
|
|
22
|
+
password: str = Field(..., min_length=8, max_length=128)
|
|
23
|
+
confirm_password: Optional[str] = None
|
|
24
|
+
accept_terms: Optional[bool] = False
|
|
25
|
+
|
|
26
|
+
@validator('confirm_password')
|
|
27
|
+
def passwords_match(cls, v, values):
|
|
28
|
+
if 'password' in values and v != values['password']:
|
|
29
|
+
raise ValueError('Passwords do not match')
|
|
30
|
+
return v
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class UserUpdate(BaseModel):
|
|
34
|
+
"""User profile update schema"""
|
|
35
|
+
first_name: Optional[str] = None
|
|
36
|
+
last_name: Optional[str] = None
|
|
37
|
+
phone_number: Optional[str] = None
|
|
38
|
+
avatar_url: Optional[str] = None
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class UserResponse(UserBase):
|
|
42
|
+
"""User response schema"""
|
|
43
|
+
id: UUID
|
|
44
|
+
is_active: bool
|
|
45
|
+
is_verified: bool
|
|
46
|
+
is_superuser: bool
|
|
47
|
+
two_factor_enabled: bool
|
|
48
|
+
created_at: datetime
|
|
49
|
+
updated_at: datetime
|
|
50
|
+
last_login_at: Optional[datetime] = None
|
|
51
|
+
|
|
52
|
+
class Config:
|
|
53
|
+
from_attributes = True
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
# Authentication schemas
|
|
57
|
+
class LoginRequest(BaseModel):
|
|
58
|
+
"""Login request schema (OAuth2 compatible)"""
|
|
59
|
+
username: EmailStr # OAuth2 spec requires 'username'
|
|
60
|
+
password: str
|
|
61
|
+
grant_type: Optional[str] = "password"
|
|
62
|
+
scope: Optional[str] = ""
|
|
63
|
+
client_id: Optional[str] = None
|
|
64
|
+
client_secret: Optional[str] = None
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class TokenResponse(BaseModel):
|
|
68
|
+
"""Token response schema (OAuth2 compatible)"""
|
|
69
|
+
access_token: str
|
|
70
|
+
refresh_token: Optional[str] = None
|
|
71
|
+
token_type: str = "bearer"
|
|
72
|
+
expires_in: Optional[int] = None
|
|
73
|
+
scope: Optional[str] = ""
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class LoginResponse(BaseModel):
|
|
77
|
+
"""Enhanced login response with user data"""
|
|
78
|
+
user: UserResponse
|
|
79
|
+
tokens: TokenResponse
|
|
80
|
+
requires_2fa: bool = False
|
|
81
|
+
message: Optional[str] = None
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class RefreshTokenRequest(BaseModel):
|
|
85
|
+
"""Refresh token request"""
|
|
86
|
+
refresh_token: str
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class LogoutRequest(BaseModel):
|
|
90
|
+
"""Logout request"""
|
|
91
|
+
refresh_token: str
|
|
92
|
+
everywhere: bool = False # Logout from all devices
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
# Password management schemas
|
|
96
|
+
class PasswordChangeRequest(BaseModel):
|
|
97
|
+
"""Password change request"""
|
|
98
|
+
current_password: str
|
|
99
|
+
new_password: str = Field(..., min_length=8, max_length=128)
|
|
100
|
+
confirm_password: Optional[str] = None
|
|
101
|
+
|
|
102
|
+
@validator('confirm_password')
|
|
103
|
+
def passwords_match(cls, v, values):
|
|
104
|
+
if 'new_password' in values and v != values['new_password']:
|
|
105
|
+
raise ValueError('Passwords do not match')
|
|
106
|
+
return v
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
class PasswordResetRequest(BaseModel):
|
|
110
|
+
"""Password reset request"""
|
|
111
|
+
email: EmailStr
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class PasswordResetConfirmRequest(BaseModel):
|
|
115
|
+
"""Password reset confirmation"""
|
|
116
|
+
token: str
|
|
117
|
+
new_password: str = Field(..., min_length=8, max_length=128)
|
|
118
|
+
confirm_password: Optional[str] = None
|
|
119
|
+
|
|
120
|
+
@validator('confirm_password')
|
|
121
|
+
def passwords_match(cls, v, values):
|
|
122
|
+
if 'new_password' in values and v != values['new_password']:
|
|
123
|
+
raise ValueError('Passwords do not match')
|
|
124
|
+
return v
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
# Email verification schemas
|
|
128
|
+
class EmailVerificationRequest(BaseModel):
|
|
129
|
+
"""Request email verification resend"""
|
|
130
|
+
email: Optional[EmailStr] = None # Use current user's email if not provided
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
# Response messages
|
|
134
|
+
class MessageResponse(BaseModel):
|
|
135
|
+
"""Generic message response"""
|
|
136
|
+
message: str
|
|
137
|
+
success: bool = True
|
|
138
|
+
data: Optional[Dict[str, Any]] = None
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
class ErrorResponse(BaseModel):
|
|
142
|
+
"""Error response"""
|
|
143
|
+
detail: str
|
|
144
|
+
code: Optional[str] = None
|
|
145
|
+
field: Optional[str] = None
|