feat(auth): implement TOTP two-factor authentication with enrollment and verification
Adds TOTP (Time-based One-Time Password) two-factor authentication support including: - New TOTP service with secret generation, QR code provisioning, and code verification - New auth endpoints for enrollment, verification, status, and backup code management - New TOTP authentication method type and user methods for TOTP management - Backup codes generation and verification for account recovery - Updated OIDC endpoints with timezone-aware datetime handling and RFC-compliant responses - Added "roles" scope support for OIDC userinfo and ID tokens - New pyotp dependency for TOTP operations - Comprehensive unit tests for TOTP service
This commit is contained in:
@@ -26,6 +26,7 @@ def setup_cors(app):
|
||||
response.headers["Access-Control-Allow-Methods"] = "GET, POST, PUT, PATCH, DELETE, OPTIONS"
|
||||
response.headers["Access-Control-Allow-Headers"] = "Content-Type, Authorization, X-Request-ID"
|
||||
response.headers["Access-Control-Max-Age"] = "3600"
|
||||
response.headers["Cache-Control"] = "no-cache, no-store"
|
||||
return response
|
||||
elif origin and origin in cors_origins:
|
||||
response = make_response("", 204)
|
||||
@@ -34,6 +35,7 @@ def setup_cors(app):
|
||||
response.headers["Access-Control-Allow-Headers"] = "Content-Type, Authorization, X-Request-ID"
|
||||
response.headers["Access-Control-Allow-Credentials"] = "true"
|
||||
response.headers["Access-Control-Max-Age"] = "3600"
|
||||
response.headers["Cache-Control"] = "no-cache, no-store"
|
||||
return response
|
||||
|
||||
@app.after_request
|
||||
|
||||
@@ -51,4 +51,15 @@ class SecurityHeadersMiddleware:
|
||||
"geolocation=(), microphone=(), camera=()"
|
||||
)
|
||||
|
||||
# Cache-Control: Allow OIDC endpoints to set their own Cache-Control
|
||||
# Only set no-cache for API responses that haven't set their own cache headers
|
||||
if "Cache-Control" not in response.headers:
|
||||
# Check if this is a JSON API response (shouldn't be cached)
|
||||
content_type = response.headers.get("Content-Type", "")
|
||||
if "application/json" in content_type:
|
||||
response.headers["Cache-Control"] = "no-cache, no-store"
|
||||
elif "text/html" not in content_type:
|
||||
# For non-HTML responses, add Pragma for HTTP/1.0 compatibility
|
||||
response.headers["Pragma"] = "no-cache"
|
||||
|
||||
return response
|
||||
|
||||
Reference in New Issue
Block a user