"""Auth endpoints: login, refresh (rotation), logout, and current-user.""" from fastapi import APIRouter, status from app.api.deps import AuthServiceDep, CurrentUser, UserServiceDep from app.api.schemas.auth import ( LoginRequest, RefreshRequest, RegisterRequest, TokenResponse, ) from app.api.schemas.user import UserResponse from app.core.config import get_settings from app.domain.errors import PermissionDeniedError from app.domain.tokens import TokenPair router = APIRouter(prefix="/auth", tags=["auth"]) def _to_token_response(pair: TokenPair) -> TokenResponse: return TokenResponse( access_token=pair.access.encoded, refresh_token=pair.refresh.encoded, ) @router.post("/login", response_model=TokenResponse) async def login(body: LoginRequest, auth: AuthServiceDep) -> TokenResponse: pair = await auth.login(body.username, body.password) return _to_token_response(pair) @router.post("/register", response_model=TokenResponse, status_code=status.HTTP_201_CREATED) async def register( body: RegisterRequest, users: UserServiceDep, auth: AuthServiceDep ) -> TokenResponse: """Public self-service sign-up (gated by ``ALLOW_REGISTRATION``). Registered accounts are always regular users — superusers are created admin-only. On success the new account is logged straight in. """ if not get_settings().allow_registration: raise PermissionDeniedError("Registration is disabled on this instance.") await users.create_user(username=body.username, password=body.password, is_superuser=False) pair = await auth.login(body.username, body.password) return _to_token_response(pair) @router.post("/refresh", response_model=TokenResponse) async def refresh(body: RefreshRequest, auth: AuthServiceDep) -> TokenResponse: pair = await auth.refresh(body.refresh_token) return _to_token_response(pair) @router.post("/logout", status_code=status.HTTP_204_NO_CONTENT) async def logout(body: RefreshRequest, auth: AuthServiceDep) -> None: await auth.logout(body.refresh_token) @router.get("/me", response_model=UserResponse) async def me(user: CurrentUser) -> UserResponse: return UserResponse.from_entity(user)