Initial commit - production deployment
This commit is contained in:
230
services/auth/app/schemas/auth.py
Normal file
230
services/auth/app/schemas/auth.py
Normal file
@@ -0,0 +1,230 @@
|
||||
# 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("admin", pattern=r'^(user|admin|manager|super_admin)$')
|
||||
subscription_plan: Optional[str] = Field("starter", description="Selected subscription plan (starter, professional, enterprise)")
|
||||
billing_cycle: Optional[str] = Field("monthly", description="Billing cycle (monthly, yearly)")
|
||||
coupon_code: Optional[str] = Field(None, description="Discount coupon code")
|
||||
payment_method_id: Optional[str] = Field(None, description="Stripe payment method ID")
|
||||
# GDPR Consent fields
|
||||
terms_accepted: Optional[bool] = Field(True, description="Accept terms of service")
|
||||
privacy_accepted: Optional[bool] = Field(True, description="Accept privacy policy")
|
||||
marketing_consent: Optional[bool] = Field(False, description="Consent to marketing communications")
|
||||
analytics_consent: Optional[bool] = Field(False, description="Consent to analytics cookies")
|
||||
|
||||
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] = "admin"
|
||||
|
||||
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
|
||||
subscription_id: Optional[str] = Field(None, description="Subscription ID if created during registration")
|
||||
# Payment action fields (3DS, SetupIntent, etc.)
|
||||
requires_action: Optional[bool] = Field(None, description="Whether payment action is required (3DS, SetupIntent confirmation)")
|
||||
action_type: Optional[str] = Field(None, description="Type of action required (setup_intent_confirmation, payment_intent_confirmation)")
|
||||
client_secret: Optional[str] = Field(None, description="Client secret for payment confirmation")
|
||||
payment_intent_id: Optional[str] = Field(None, description="Payment intent ID for 3DS authentication")
|
||||
setup_intent_id: Optional[str] = Field(None, description="SetupIntent ID for payment method verification")
|
||||
customer_id: Optional[str] = Field(None, description="Stripe customer ID")
|
||||
# Additional fields for post-confirmation subscription completion
|
||||
plan_id: Optional[str] = Field(None, description="Subscription plan ID")
|
||||
payment_method_id: Optional[str] = Field(None, description="Payment method ID")
|
||||
trial_period_days: Optional[int] = Field(None, description="Trial period in days")
|
||||
user_id: Optional[str] = Field(None, description="User ID for post-confirmation processing")
|
||||
billing_interval: Optional[str] = Field(None, description="Billing interval (monthly, yearly)")
|
||||
message: Optional[str] = Field(None, description="Additional message about payment action required")
|
||||
|
||||
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"
|
||||
},
|
||||
"subscription_id": "sub_1234567890",
|
||||
"requires_action": True,
|
||||
"action_type": "setup_intent_confirmation",
|
||||
"client_secret": "seti_1234_secret_5678",
|
||||
"payment_intent_id": None,
|
||||
"setup_intent_id": "seti_1234567890",
|
||||
"customer_id": "cus_1234567890"
|
||||
}
|
||||
}
|
||||
|
||||
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] = "admin"
|
||||
payment_customer_id: Optional[str] = None # ✅ Added payment integration field
|
||||
default_payment_method_id: Optional[str] = None # ✅ Added payment integration field
|
||||
|
||||
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] = ["admin"]
|
||||
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
|
||||
Reference in New Issue
Block a user