Files
bakery-ia/services/auth/app/schemas/auth.py
Urtzi Alfaro 277e8bec73 Add user role
2025-08-02 09:41:50 +02:00

194 lines
5.9 KiB
Python

# services/auth/app/schemas/auth.py - UPDATED WITH UNIFIED TOKEN RESPONSE
"""
Authentication schemas - Updated with unified token response format
Following industry best practices from Firebase, Cognito, etc.
"""
from pydantic import BaseModel, EmailStr, Field
from typing import Optional, Dict, Any
from datetime import datetime
# ================================================================
# REQUEST SCHEMAS
# ================================================================
class UserRegistration(BaseModel):
"""User registration request"""
email: EmailStr
password: str = Field(..., min_length=8, max_length=128)
full_name: str = Field(..., min_length=1, max_length=255)
tenant_name: Optional[str] = Field(None, max_length=255)
role: Optional[str] = Field("user", pattern=r'^(user|admin|manager)$')
class UserLogin(BaseModel):
"""User login request"""
email: EmailStr
password: str
class RefreshTokenRequest(BaseModel):
"""Refresh token request"""
refresh_token: str
class PasswordChange(BaseModel):
"""Password change request"""
current_password: str
new_password: str = Field(..., min_length=8, max_length=128)
class PasswordReset(BaseModel):
"""Password reset request"""
email: EmailStr
class PasswordResetConfirm(BaseModel):
"""Password reset confirmation"""
token: str
new_password: str = Field(..., min_length=8, max_length=128)
# ================================================================
# RESPONSE SCHEMAS
# ================================================================
class UserData(BaseModel):
"""User data embedded in token responses"""
id: str
email: str
full_name: str
is_active: bool
is_verified: bool
created_at: str # ISO format datetime string
tenant_id: Optional[str] = None
role: Optional[str] = "user"
class TokenResponse(BaseModel):
"""
Unified token response for both registration and login
Follows industry standards (Firebase, AWS Cognito, etc.)
"""
access_token: str
refresh_token: Optional[str] = None
token_type: str = "bearer"
expires_in: int = 3600 # seconds
user: Optional[UserData] = None
class Config:
schema_extra = {
"example": {
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "def502004b8b7f8f...",
"token_type": "bearer",
"expires_in": 3600,
"user": {
"id": "123e4567-e89b-12d3-a456-426614174000",
"email": "user@example.com",
"full_name": "John Doe",
"is_active": True,
"is_verified": False,
"created_at": "2025-07-22T10:00:00Z",
"role": "user"
}
}
}
class UserResponse(BaseModel):
"""User response for user management endpoints - FIXED"""
id: str
email: str
full_name: str
is_active: bool
is_verified: bool
created_at: datetime # ✅ Changed from str to datetime
last_login: Optional[datetime] = None # ✅ Added missing field
phone: Optional[str] = None # ✅ Added missing field
language: Optional[str] = None # ✅ Added missing field
timezone: Optional[str] = None # ✅ Added missing field
tenant_id: Optional[str] = None
role: Optional[str] = "user"
class Config:
from_attributes = True # ✅ Enable ORM mode for SQLAlchemy objects
class TokenVerification(BaseModel):
"""Token verification response"""
valid: bool
user_id: Optional[str] = None
email: Optional[str] = None
exp: Optional[int] = None
message: Optional[str] = None
class PasswordResetResponse(BaseModel):
"""Password reset response"""
message: str
reset_token: Optional[str] = None
class LogoutResponse(BaseModel):
"""Logout response"""
message: str
success: bool = True
# ================================================================
# ERROR SCHEMAS
# ================================================================
class ErrorDetail(BaseModel):
"""Error detail for API responses"""
message: str
code: Optional[str] = None
field: Optional[str] = None
class ErrorResponse(BaseModel):
"""Standardized error response"""
success: bool = False
error: ErrorDetail
timestamp: str
class Config:
schema_extra = {
"example": {
"success": False,
"error": {
"message": "Invalid credentials",
"code": "AUTH_001"
},
"timestamp": "2025-07-22T10:00:00Z"
}
}
# ================================================================
# VALIDATION SCHEMAS
# ================================================================
class EmailVerificationRequest(BaseModel):
"""Email verification request"""
email: EmailStr
class EmailVerificationConfirm(BaseModel):
"""Email verification confirmation"""
token: str
class ProfileUpdate(BaseModel):
"""Profile update request"""
full_name: Optional[str] = Field(None, min_length=1, max_length=255)
email: Optional[EmailStr] = None
# ================================================================
# INTERNAL SCHEMAS (for service communication)
# ================================================================
class UserContext(BaseModel):
"""User context for internal service communication"""
user_id: str
email: str
tenant_id: Optional[str] = None
roles: list[str] = ["user"]
is_verified: bool = False
class TokenClaims(BaseModel):
"""JWT token claims structure"""
sub: str # subject (user_id)
email: str
full_name: str
user_id: str
is_verified: bool
tenant_id: Optional[str] = None
iat: int # issued at
exp: int # expires at
iss: str = "bakery-auth" # issuer