""" Web Session model for passwordless authentication Represents an authenticated web session after device approval """ from datetime import datetime from typing import Optional, Dict, Any from enum import Enum from pydantic import BaseModel, Field import uuid class WebSessionStatus(str, Enum): """Web session status""" ACTIVE = "active" EXPIRED = "expired" LOGGED_OUT = "logged_out" REVOKED = "revoked" class WebSession(BaseModel): """Web session database model""" id: str = Field(default_factory=lambda: str(uuid.uuid4())) # Session identifiers session_token: str = Field(..., description="JWT session token") refresh_token: str = Field(..., description="Refresh token for session renewal") # User info user_id: str = Field(..., description="Authenticated user ID") auth_request_id: str = Field(..., description="Reference to auth request") device_id: str = Field(..., description="Device that approved the login") # Status status: WebSessionStatus = Field(default=WebSessionStatus.ACTIVE) # Security context ip_address: Optional[str] = Field(None) user_agent: Optional[str] = Field(None) browser_fingerprint: Optional[str] = Field(None) device_fingerprint: Optional[str] = Field(None) # Session metadata metadata: Dict[str, Any] = Field(default_factory=dict) # Timestamps created_at: datetime = Field(default_factory=datetime.utcnow) expires_at: datetime = Field(..., description="Session expiration") last_activity_at: datetime = Field(default_factory=datetime.utcnow) logged_out_at: Optional[datetime] = Field(None) class Config: json_schema_extra = { "example": { "id": "ws_123456", "session_token": "eyJhbGciOiJIUzI1NiIs...", "refresh_token": "rt_abc123...", "user_id": "user_abc123", "auth_request_id": "auth_req_123", "device_id": "dev_123456789", "status": "active", "created_at": "2024-01-15T10:30:00Z", "expires_at": "2024-01-15T18:30:00Z", "last_activity_at": "2024-01-15T10:35:00Z" } } class WebSessionCreate(BaseModel): """Request model for creating web session""" user_id: str auth_request_id: str device_id: str ip_address: Optional[str] = None user_agent: Optional[str] = None browser_fingerprint: Optional[str] = None device_fingerprint: Optional[str] = None metadata: Dict[str, Any] = Field(default_factory=dict) class WebSessionResponse(BaseModel): """Response model for web session""" id: str user_id: str device_id: str status: WebSessionStatus created_at: datetime expires_at: datetime last_activity_at: datetime class Config: from_attributes = True class WebSessionTokenResponse(BaseModel): """Response model for session tokens""" access_token: str = Field(..., description="JWT access token") refresh_token: str = Field(..., description="Refresh token") token_type: str = Field(default="Bearer") expires_in: int = Field(..., description="Token expiration in seconds") session_id: str class WebSessionCompleteRequest(BaseModel): """Request model for completing web session""" request_token: str = Field(..., description="Auth request token") browser_fingerprint: Optional[str] = Field(None) user_agent: Optional[str] = Field(None) ip_address: Optional[str] = Field(None) class WebSessionRefreshRequest(BaseModel): """Request model for refreshing session""" refresh_token: str = Field(..., description="Valid refresh token") class WebSessionLogoutRequest(BaseModel): """Request model for logging out""" session_token: str = Field(..., description="Session token to invalidate") all_sessions: bool = Field(default=False, description="Logout all user sessions")