Source code for florist.api.routes.client.auth

"""FastAPI client routes for authentication."""

import logging
from typing import Annotated

from fastapi import APIRouter, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from jwt.exceptions import InvalidTokenError

from florist.api.auth.token import (
    DEFAULT_USERNAME,
    AuthUser,
    Token,
    create_access_token,
    decode_access_token,
    verify_password,
)
from florist.api.db.client_entities import UserDAO


LOGGER = logging.getLogger("uvicorn.error")

router = APIRouter()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="api/client/auth/token")


[docs] @router.post("/token") async def login_for_access_token(form_data: Annotated[OAuth2PasswordRequestForm, Depends()]) -> Token: """ Make a login request to get an access token. :param form_data: (OAuth2PasswordRequestForm) The form data from the login request. :return: (Token) The access token. :raise: (HTTPException) If the user does not exist or the password is incorrect. """ credentials_exception = HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Incorrect username or password.", headers={"WWW-Authenticate": "Bearer"}, ) try: user = UserDAO.find(form_data.username) if not verify_password(form_data.password, user.hashed_password): raise credentials_exception access_token = create_access_token(data={"sub": user.username}, secret_key=user.secret_key) return Token(access_token=access_token, token_type="bearer") except ValueError as err: credentials_exception.detail = str(err) raise credentials_exception from err
[docs] @router.get("/check_default_user_token", response_model=AuthUser) async def check_default_user_token(token: Annotated[str, Depends(oauth2_scheme)]) -> AuthUser: """ Validate the default user against the token. :param token: (str) The token to validate the current user. :return: (AuthUser) The current authenticated user. :raise: (HTTPException) If the token is invalid. """ credentials_exception = HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Could not validate credentials", headers={"WWW-Authenticate": "Bearer"}, ) try: user = UserDAO.find(DEFAULT_USERNAME) payload = decode_access_token(token, user.secret_key) username = payload.get("sub") if username is None or username != user.username: raise credentials_exception return AuthUser(uuid=user.uuid, username=user.username) except InvalidTokenError as err: raise credentials_exception from err except ValueError as err: raise credentials_exception from err