first commit
This commit is contained in:
93
app/schemas/client.py
Normal file
93
app/schemas/client.py
Normal file
@ -0,0 +1,93 @@
|
||||
"""
|
||||
Client Schemas
|
||||
|
||||
Pydantic schemas for OIDC client-related requests and responses.
|
||||
"""
|
||||
|
||||
from pydantic import BaseModel, Field, field_validator
|
||||
from typing import List, Optional
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
# ==========================================
|
||||
# Base Schemas
|
||||
# ==========================================
|
||||
|
||||
class ClientBase(BaseModel):
|
||||
"""Base client schema with common fields."""
|
||||
client_name: str = Field(..., min_length=1, max_length=255, description="Client application name")
|
||||
redirect_uris: List[str] = Field(..., min_items=1, description="List of allowed redirect URIs")
|
||||
allowed_scopes: List[str] = Field(default_factory=lambda: ["openid", "profile", "email"], description="Allowed OAuth scopes")
|
||||
|
||||
|
||||
# ==========================================
|
||||
# Request Schemas (Input)
|
||||
# ==========================================
|
||||
|
||||
class ClientCreate(ClientBase):
|
||||
"""Schema for creating a new OIDC client."""
|
||||
client_id: Optional[str] = Field(None, description="Client ID (auto-generated if not provided)")
|
||||
client_secret: Optional[str] = Field(None, description="Client secret (auto-generated if not provided)")
|
||||
|
||||
@field_validator('redirect_uris')
|
||||
@classmethod
|
||||
def validate_redirect_uris(cls, v: List[str]) -> List[str]:
|
||||
"""Validate redirect URIs."""
|
||||
if not v:
|
||||
raise ValueError('At least one redirect URI is required')
|
||||
|
||||
for uri in v:
|
||||
if not uri.startswith(('http://', 'https://')):
|
||||
raise ValueError(f'Invalid redirect URI: {uri}. Must start with http:// or https://')
|
||||
|
||||
return v
|
||||
|
||||
|
||||
class ClientUpdate(BaseModel):
|
||||
"""Schema for updating an OIDC client."""
|
||||
client_name: Optional[str] = Field(None, min_length=1, max_length=255)
|
||||
redirect_uris: Optional[List[str]] = None
|
||||
allowed_scopes: Optional[List[str]] = None
|
||||
new_client_secret: Optional[str] = Field(None, description="New client secret (optional)")
|
||||
|
||||
@field_validator('redirect_uris')
|
||||
@classmethod
|
||||
def validate_redirect_uris(cls, v: Optional[List[str]]) -> Optional[List[str]]:
|
||||
"""Validate redirect URIs if provided."""
|
||||
if v is not None:
|
||||
if not v:
|
||||
raise ValueError('At least one redirect URI is required')
|
||||
|
||||
for uri in v:
|
||||
if not uri.startswith(('http://', 'https://')):
|
||||
raise ValueError(f'Invalid redirect URI: {uri}')
|
||||
|
||||
return v
|
||||
|
||||
|
||||
# ==========================================
|
||||
# Response Schemas (Output)
|
||||
# ==========================================
|
||||
|
||||
class ClientResponse(BaseModel):
|
||||
"""Schema for client responses."""
|
||||
id: int
|
||||
client_id: str
|
||||
client_name: str
|
||||
redirect_uris: List[str]
|
||||
allowed_scopes: List[str]
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
|
||||
class ClientWithSecret(ClientResponse):
|
||||
"""Schema for client response including secret (only for creation)."""
|
||||
client_secret: str = Field(..., description="Client secret (only shown once)")
|
||||
|
||||
|
||||
class ClientListResponse(BaseModel):
|
||||
"""Schema for client list."""
|
||||
clients: List[ClientResponse]
|
||||
total: int
|
||||
Reference in New Issue
Block a user