Files
MAIA/backend/modules/auth/api.py
2025-04-16 21:32:57 +02:00

74 lines
3.2 KiB
Python

# modules/auth/api.py
from fastapi import APIRouter, Cookie, Depends, HTTPException, status, Request, Response
from fastapi.security import OAuth2PasswordRequestForm
from jose import JWTError
from modules.auth.models import User
from modules.auth.schemas import UserCreate, UserResponse, Token
from modules.auth.services import create_user
from modules.auth.security import TokenType, get_current_user, oauth2_scheme, create_access_token, create_refresh_token, verify_token, authenticate_user, blacklist_tokens
from sqlalchemy.orm import Session
from typing import Annotated, Optional
from core.database import get_db
from datetime import timedelta
from core.config import settings # Assuming settings is defined in core.config
from core.exceptions import unauthorized_exception
router = APIRouter()
@router.post("/register", response_model=UserResponse, status_code=status.HTTP_201_CREATED)
def register(user: UserCreate, db: Annotated[Session, Depends(get_db)]):
return create_user(user.username, user.password, user.name, db)
@router.post("/login", response_model=Token)
def login(response: Response, form_data: Annotated[OAuth2PasswordRequestForm, Depends()], db: Annotated[Session, Depends(get_db)]):
"""
Authenticate user and return JWT token.
"""
user = authenticate_user(form_data.username, form_data.password, db)
if not user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect username or password",
)
access_token = create_access_token(data={"sub": user.username}, expires_delta=timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES))
refresh_token = create_refresh_token(data={"sub": user.username})
max_age = settings.REFRESH_TOKEN_EXPIRE_DAYS * 24 * 60 * 60
response.set_cookie(
key="refresh_token", value=refresh_token, httponly=True, secure=True, samesite="Lax", max_age=max_age
)
return {"access_token": access_token, "token_type": "bearer"}
@router.post("/refresh")
def refresh_token(request: Request, db: Annotated[Session, Depends(get_db)]):
refresh_token = request.cookies.get("refresh_token")
if not refresh_token:
raise unauthorized_exception("Refresh token missing")
user_data = verify_token(refresh_token, expected_token_type=TokenType.REFRESH, db=db)
if not user_data:
raise unauthorized_exception("Invalid refresh token")
new_access_token = create_access_token(data={"sub": user_data.username})
return {"access_token": new_access_token, "token_type": "bearer"}
@router.post("/logout")
def logout(response: Response, db: Annotated[Session, Depends(get_db)], current_user: Annotated[User, Depends(get_current_user)], access_token: str = Depends(oauth2_scheme), refresh_token: Optional[str] = Cookie(None, alias="refresh_token")):
try:
if not refresh_token:
raise unauthorized_exception("Refresh token not found")
blacklist_tokens(
access_token=access_token,
refresh_token=refresh_token,
db=db
)
response.delete_cookie(key="refresh_token")
return {"message": "Logged out successfully"}
except JWTError:
raise unauthorized_exception("Invalid token")