From f7d9b9c5ad6bb3894a4fd0a14f0270b6aa4b5a7d Mon Sep 17 00:00:00 2001 From: Guilherme Souza Date: Tue, 1 Sep 2026 12:28:43 -0300 Subject: [PATCH] fix(auth): stop putting the raw JWT in UserDoesntExist UserDoesntExist stored the access token and never called Exception.__init__ with a message. BaseException.__new__ still set args = (access_token,), so str(e) and every traceback line printed the raw user JWT into logs and error trackers. The class now takes no arguments and carries a fixed, non-secret message. It also derives from CustomAuthError instead of Exception, so `except AuthError` catches it like every other auth error. BREAKING CHANGE: UserDoesntExist() takes no arguments and no longer has an .access_token attribute. --- .../src/supabase_auth/_async/gotrue_client.py | 4 ++-- .../src/supabase_auth/_sync/gotrue_client.py | 4 ++-- src/auth/src/supabase_auth/errors.py | 16 +++++++++++----- src/auth/tests/test_errors.py | 9 +++++++++ 4 files changed, 24 insertions(+), 9 deletions(-) create mode 100644 src/auth/tests/test_errors.py diff --git a/src/auth/src/supabase_auth/_async/gotrue_client.py b/src/auth/src/supabase_auth/_async/gotrue_client.py index 5ee1670b..269e38b7 100644 --- a/src/auth/src/supabase_auth/_async/gotrue_client.py +++ b/src/auth/src/supabase_auth/_async/gotrue_client.py @@ -750,7 +750,7 @@ async def set_session(self, access_token: str, refresh_token: str) -> AuthRespon else: user_response = await self.get_user(access_token) if user_response is None: - raise UserDoesntExist(access_token) + raise UserDoesntExist() session = Session( access_token=access_token, refresh_token=refresh_token, @@ -1025,7 +1025,7 @@ async def _get_session_from_url( expires_at = time_now + int(expires_in) user = await self.get_user(access_token) if user is None: - raise UserDoesntExist(access_token) + raise UserDoesntExist() session = Session( provider_token=provider_token, provider_refresh_token=provider_refresh_token, diff --git a/src/auth/src/supabase_auth/_sync/gotrue_client.py b/src/auth/src/supabase_auth/_sync/gotrue_client.py index 063d1ddb..efaa1089 100644 --- a/src/auth/src/supabase_auth/_sync/gotrue_client.py +++ b/src/auth/src/supabase_auth/_sync/gotrue_client.py @@ -746,7 +746,7 @@ def set_session(self, access_token: str, refresh_token: str) -> AuthResponse: else: user_response = self.get_user(access_token) if user_response is None: - raise UserDoesntExist(access_token) + raise UserDoesntExist() session = Session( access_token=access_token, refresh_token=refresh_token, @@ -1019,7 +1019,7 @@ def _get_session_from_url( expires_at = time_now + int(expires_in) user = self.get_user(access_token) if user is None: - raise UserDoesntExist(access_token) + raise UserDoesntExist() session = Session( provider_token=provider_token, provider_refresh_token=provider_refresh_token, diff --git a/src/auth/src/supabase_auth/errors.py b/src/auth/src/supabase_auth/errors.py index e7a10539..d137b9fa 100644 --- a/src/auth/src/supabase_auth/errors.py +++ b/src/auth/src/supabase_auth/errors.py @@ -90,11 +90,6 @@ ] -class UserDoesntExist(Exception): - def __init__(self, access_token: str) -> None: - self.access_token = access_token - - class AuthError(Exception): def __init__(self, message: str, code: ErrorCode | None) -> None: Exception.__init__(self, message) @@ -150,6 +145,17 @@ def to_dict(self) -> AuthApiErrorDict: } +class UserDoesntExist(CustomAuthError): + def __init__(self) -> None: + CustomAuthError.__init__( + self, + "User does not exist for the provided access token", + "UserDoesntExist", + 404, + "user_not_found", + ) + + class AuthSessionMissingError(CustomAuthError): def __init__(self) -> None: CustomAuthError.__init__( diff --git a/src/auth/tests/test_errors.py b/src/auth/tests/test_errors.py new file mode 100644 index 00000000..391d8deb --- /dev/null +++ b/src/auth/tests/test_errors.py @@ -0,0 +1,9 @@ +from supabase_auth.errors import AuthError, UserDoesntExist + + +def test_user_doesnt_exist_never_carries_the_token() -> None: + error = UserDoesntExist() + assert isinstance(error, AuthError) + assert str(error) == "User does not exist for the provided access token" + assert error.args == ("User does not exist for the provided access token",) + assert not hasattr(error, "access_token")