Build and Push / build (release) Successful in 50s
- GET /auth/groups - list groups with search/pagination - POST /auth/groups/sync-from-authentik - bulk sync from Authentik - Group model and database migration 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
130 lines
4.9 KiB
Python
130 lines
4.9 KiB
Python
"""
|
|
Authentication Schemas
|
|
|
|
Pydantic models for auth request/response payloads.
|
|
"""
|
|
import uuid
|
|
from datetime import datetime
|
|
from typing import Optional
|
|
from pydantic import Field
|
|
|
|
from src.base_schema import BaseSchema
|
|
|
|
|
|
class AuthSyncRequest(BaseSchema):
|
|
"""
|
|
Request payload for POST /auth/sync
|
|
|
|
The client sends this after obtaining an OIDC token from Authentik.
|
|
The access_token is validated against Authentik's userinfo endpoint.
|
|
"""
|
|
|
|
access_token: str = Field(
|
|
...,
|
|
description="OIDC access token from Authentik",
|
|
)
|
|
|
|
|
|
class RoleSchema(BaseSchema):
|
|
"""Role information in domain:action format"""
|
|
|
|
name: str = Field(..., description="Role name (e.g., 'control-room:admin')")
|
|
domain: str = Field(..., description="Permission domain (e.g., 'control-room')")
|
|
action: str = Field(..., description="Permission action (e.g., 'admin')")
|
|
|
|
|
|
class UserPreferencesSchema(BaseSchema):
|
|
"""User preferences"""
|
|
|
|
theme: str = Field(default="system", description="Theme preference: system, light, dark")
|
|
default_room: str = Field(default="front-hall", description="Default room for housekeeping")
|
|
preferences_json: dict = Field(default_factory=dict, description="Extended preferences")
|
|
|
|
|
|
class UserSchema(BaseSchema):
|
|
"""User information returned from sync"""
|
|
|
|
id: uuid.UUID = Field(..., description="Internal user ID")
|
|
authentik_id: uuid.UUID = Field(..., description="Authentik user ID")
|
|
email: str = Field(..., description="User email")
|
|
name: str = Field(..., description="Display name")
|
|
avatar_url: Optional[str] = Field(None, description="Profile picture URL")
|
|
created_at: datetime = Field(..., description="Account creation timestamp")
|
|
last_login: Optional[datetime] = Field(None, description="Last login timestamp")
|
|
|
|
|
|
class AuthSyncResponse(BaseSchema):
|
|
"""
|
|
Response from POST /auth/sync
|
|
|
|
Contains the synced user profile, roles, and preferences.
|
|
"""
|
|
|
|
user: UserSchema = Field(..., description="User profile")
|
|
roles: list[RoleSchema] = Field(..., description="User's permission roles")
|
|
preferences: UserPreferencesSchema = Field(..., description="User preferences")
|
|
is_new_user: bool = Field(..., description="True if user was just created")
|
|
|
|
|
|
class TokenInfoSchema(BaseSchema):
|
|
"""
|
|
Token information from Authentik userinfo endpoint
|
|
|
|
This is what Authentik returns when validating an access token.
|
|
"""
|
|
|
|
sub: str = Field(..., description="Subject (Authentik user ID)")
|
|
email: str = Field(..., description="User email")
|
|
name: Optional[str] = Field(None, description="Display name")
|
|
preferred_username: Optional[str] = Field(None, description="Username")
|
|
groups: list[str] = Field(default_factory=list, description="Group memberships")
|
|
picture: Optional[str] = Field(None, description="Profile picture URL")
|
|
|
|
|
|
class UserListItemSchema(BaseSchema):
|
|
"""User item for list display"""
|
|
|
|
id: uuid.UUID = Field(..., description="Internal user ID")
|
|
email: str = Field(..., description="User email")
|
|
name: str = Field(..., description="Display name")
|
|
avatar_url: Optional[str] = Field(None, description="Profile picture URL")
|
|
created_at: datetime = Field(..., description="Account creation timestamp")
|
|
last_login: Optional[datetime] = Field(None, description="Last login timestamp")
|
|
roles: list[str] = Field(default_factory=list, description="Role names")
|
|
|
|
|
|
class UsersListResponse(BaseSchema):
|
|
"""Response from GET /auth/users"""
|
|
|
|
items: list[UserListItemSchema] = Field(..., description="List of users")
|
|
total: int = Field(..., description="Total count of users")
|
|
|
|
|
|
class BulkSyncResultSchema(BaseSchema):
|
|
"""Result from bulk sync operation"""
|
|
|
|
created: int = Field(..., description="Number of users created")
|
|
updated: int = Field(..., description="Number of users updated")
|
|
failed: int = Field(..., description="Number of users that failed to sync")
|
|
total_in_authentik: int = Field(..., description="Total users in Authentik")
|
|
errors: list[str] = Field(default_factory=list, description="Error messages for failed syncs")
|
|
|
|
|
|
class GroupListItemSchema(BaseSchema):
|
|
"""Group item for list display"""
|
|
|
|
id: uuid.UUID = Field(..., description="Internal group ID")
|
|
authentik_id: uuid.UUID = Field(..., description="Authentik group ID")
|
|
name: str = Field(..., description="Group name")
|
|
is_superuser: bool = Field(default=False, description="Whether group has superuser privileges")
|
|
parent_name: Optional[str] = Field(None, description="Parent group name")
|
|
member_count: int = Field(default=0, description="Number of users in this group")
|
|
synced_at: datetime = Field(..., description="Last sync timestamp")
|
|
|
|
|
|
class GroupsListResponse(BaseSchema):
|
|
"""Response from GET /auth/groups"""
|
|
|
|
items: list[GroupListItemSchema] = Field(..., description="List of groups")
|
|
total: int = Field(..., description="Total count of groups")
|