from typing import Annotated from fastapi import APIRouter, Depends, HTTPException, status from jose import JWTError from sqlalchemy.ext.asyncio import AsyncSession from app.core.deps import CurrentUser, get_session from app.core.security import TOKEN_TYPE_REFRESH, create_access_token, create_refresh_token, decode_token from app.crud.user import crud_user from app.schemas.auth import AccessTokenResponse, LoginRequest, RefreshRequest, TokenResponse from app.schemas.user import UserRead router = APIRouter(prefix="/auth", tags=["Authentifizierung"]) @router.post("/login", response_model=TokenResponse) async def login( body: LoginRequest, db: Annotated[AsyncSession, Depends(get_session)], ) -> TokenResponse: user = await crud_user.authenticate(db, email=body.email, password=body.password) if not user: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="E-Mail oder Passwort falsch.", ) if not user.is_active: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Benutzerkonto ist deaktiviert.", ) tenants = await crud_user.get_tenants(db, user_id=user.id) return TokenResponse( access_token=create_access_token(str(user.id)), refresh_token=create_refresh_token(str(user.id)), user=UserRead.model_validate(user), tenants=tenants, ) @router.post("/refresh", response_model=AccessTokenResponse) async def refresh_token( body: RefreshRequest, db: Annotated[AsyncSession, Depends(get_session)], ) -> AccessTokenResponse: try: payload = decode_token(body.refresh_token) if payload.get("type") != TOKEN_TYPE_REFRESH: raise JWTError("Falscher Token-Typ") user_id: str = payload["sub"] except JWTError: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Ungültiger oder abgelaufener Refresh-Token.", ) from uuid import UUID user = await crud_user.get(db, id=UUID(user_id)) if not user or not user.is_active: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Benutzer nicht gefunden oder deaktiviert.", ) return AccessTokenResponse(access_token=create_access_token(user_id)) @router.get("/me", response_model=UserRead) async def get_me(current_user: CurrentUser) -> UserRead: return UserRead.model_validate(current_user)