6989a98d75
- Arkitektur: docs/auth/passwordless-architecture.md - Backend: iom/quixzoom-auth-service/ (FastAPI + Redis) - Webb: quixzoom-market-pages/se/login/ (QR-kod + polling) - App: iom/quixzoom-app/src/features/auth/ (push + deep links) Flöde: QR-kod → app-godkännande → webb-inloggad
120 lines
3.9 KiB
Python
120 lines
3.9 KiB
Python
"""
|
|
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") |