diff --git a/src/api/auth/jwt.py b/src/api/auth/jwt.py index 6d16a2f..ed97480 100644 --- a/src/api/auth/jwt.py +++ b/src/api/auth/jwt.py @@ -2,6 +2,7 @@ from datetime import UTC, datetime, timedelta from enum import StrEnum from typing import Literal, NotRequired, TypedDict, cast, final +from beanie import Link from jose import JWTError, jwt from src.db.models import user @@ -34,6 +35,7 @@ class AuthErrState(StrEnum): EXPIRED = "The provided token is expired." UNTRACKED = "The provided token isn't tracked by the server" REVOKED = "The provided token was revoked" + NO_USER = "The provided token doesn't have a user linked to it" @final @@ -123,6 +125,13 @@ async def resolve_jwt_token(token: str) -> tuple[TokenData, Token]: # We'll definitely end up needing the user, so we might as well fetch it now await db_token.fetch_link(Token.user) + # If we still get a link here, it means the user was deleted + # this shouldn't happen though, as with a user deletion, their tokens should + # also be deleted. Nevertheless, let's check it for sanity. + if isinstance(db_token.user, Link): + log.error(f"Got a token of a deleted user: {token=!r} user_id={db_token.user.ref.id!r}") + raise InvalidTokenError(AuthErrState.NO_USER, token) + return decoded, db_token