Skip to content

fix(auth): stop putting the raw JWT in UserDoesntExist - #1602

Open
grdsdev wants to merge 1 commit into
mainfrom
claude/auth-userdoesntexist-jwt-exception-104669
Open

fix(auth): stop putting the raw JWT in UserDoesntExist#1602
grdsdev wants to merge 1 commit into
mainfrom
claude/auth-userdoesntexist-jwt-exception-104669

Conversation

@grdsdev

@grdsdev grdsdev commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Closes SDK-1678.

The problem

UserDoesntExist stored the access token and never called Exception.__init__ with a message:

class UserDoesntExist(Exception):
    def __init__(self, access_token: str) -> None:
        self.access_token = access_token

BaseException.__new__ still sets args = (access_token,). So str(e) and every traceback line printed the raw user JWT. It reached application logs, error trackers, and any traceback shown to an end user.

It is raised from set_session and _get_session_from_url, in both the async and sync clients.

Second problem: the class derived from Exception, not AuthError. So except AuthError did not catch it, unlike every other auth error in the module.

The change

  • UserDoesntExist now takes no arguments and passes a fixed, non-secret message to super().__init__.
  • It derives from CustomAuthError (status 404, code user_not_found), so it joins the documented hierarchy.
  • Both call sites updated, in _async and the generated _sync twin.
  • New test in src/auth/tests/test_errors.py fails if the token comes back through args, str(), or an attribute. It needs no docker infra.

Breaking change

UserDoesntExist() takes no arguments, and the .access_token attribute is gone. Nothing in this repo read that attribute. Callers who construct the error or read the token must update.

Note for the reviewer

I did not run make build-sync in the commit. The local black/ruff reflows about ten unrelated blocks in the generated _sync files, which would bury the real change. I applied the same two-line edit to _sync/gotrue_client.py by hand instead. The formatting drift is worth a separate fix.

Checks

  • pytest src/auth/tests/test_errors.py passes.
  • mypy clean on the changed files.
  • ruff check and ruff format --check clean on the changed files.

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.
@grdsdev
grdsdev requested review from a team and o-santi as code owners September 1, 2026 15:29
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

⚠️ Capability matrix drift detected

The following capabilities are marked implemented in the matrix but could not be found in python:

  • database.configuration.auto_retry → expected symbol: AsyncSelectRequestBuilder.retry
  • database.configuration.auto_retry → expected symbol: SyncSelectRequestBuilder.retry
  • realtime.client.connect → expected symbol: SyncRealtimeClient.connect
  • realtime.client.disconnect → expected symbol: AsyncRealtimeClient.disconnect
  • realtime.client.disconnect → expected symbol: SyncRealtimeClient.disconnect
  • realtime.channel.subscribe → expected symbol: SyncRealtimeChannel.subscribe
  • realtime.channel.unsubscribe → expected symbol: SyncRealtimeChannel.unsubscribe
  • realtime.channel.broadcast → expected symbol: SyncRealtimeChannel.send_broadcast
  • realtime.subscriptions.broadcast → expected symbol: SyncRealtimeChannel.on_broadcast
  • realtime.subscriptions.postgres_changes → expected symbol: SyncRealtimeChannel.on_postgres_changes
  • realtime.subscriptions.subscribe_presence → expected symbol: AsyncRealtimeChannel.on_presence_change
  • realtime.subscriptions.subscribe_presence → expected symbol: SyncRealtimeChannel.on_presence_change
  • realtime.presence.track → expected symbol: SyncRealtimeChannel.track
  • realtime.presence.untrack → expected symbol: SyncRealtimeChannel.untrack
  • realtime.presence.presence_state → expected symbol: AsyncRealtimeChannel.presences
  • realtime.presence.presence_state → expected symbol: SyncRealtimeChannel.presences

The following capabilities are marked implemented in python but have no registered symbols to verify:

  • auth.session.auto_refresh (no symbols list — cannot confirm implementation exists)
  • client.authentication_integration.cross_client_token_sync (no symbols list — cannot confirm implementation exists)
  • client.authentication_integration.oauth_flow_type (no symbols list — cannot confirm implementation exists)
  • client.session_management.custom_storage (no symbols list — cannot confirm implementation exists)
  • client.session_management.persist_session (no symbols list — cannot confirm implementation exists)
  • client.request_configuration.custom_http_client (no symbols list — cannot confirm implementation exists)
  • client.request_configuration.global_headers (no symbols list — cannot confirm implementation exists)
  • database.mutate.select_after_mutation (no symbols list — cannot confirm implementation exists)
  • database.using_filters.eq (no symbols list — cannot confirm implementation exists)
  • database.using_filters.neq (no symbols list — cannot confirm implementation exists)
  • database.using_filters.gt (no symbols list — cannot confirm implementation exists)
  • database.using_filters.gte (no symbols list — cannot confirm implementation exists)
  • database.using_filters.lt (no symbols list — cannot confirm implementation exists)
  • database.using_filters.lte (no symbols list — cannot confirm implementation exists)
  • database.using_filters.like (no symbols list — cannot confirm implementation exists)
  • database.using_filters.ilike (no symbols list — cannot confirm implementation exists)
  • database.using_filters.is (no symbols list — cannot confirm implementation exists)
  • database.using_filters.in (no symbols list — cannot confirm implementation exists)
  • database.using_filters.contains (no symbols list — cannot confirm implementation exists)
  • database.using_filters.contained_by (no symbols list — cannot confirm implementation exists)
  • database.using_filters.range_gt (no symbols list — cannot confirm implementation exists)
  • database.using_filters.range_gte (no symbols list — cannot confirm implementation exists)
  • database.using_filters.range_lt (no symbols list — cannot confirm implementation exists)
  • database.using_filters.range_lte (no symbols list — cannot confirm implementation exists)
  • database.using_filters.range_adjacent (no symbols list — cannot confirm implementation exists)
  • database.using_filters.overlaps (no symbols list — cannot confirm implementation exists)
  • database.using_filters.text_search (no symbols list — cannot confirm implementation exists)
  • database.using_filters.match (no symbols list — cannot confirm implementation exists)
  • database.using_filters.not (no symbols list — cannot confirm implementation exists)
  • database.using_filters.or (no symbols list — cannot confirm implementation exists)
  • database.using_filters.raw (no symbols list — cannot confirm implementation exists)
  • database.using_filters.regex (no symbols list — cannot confirm implementation exists)
  • database.using_filters.regex_icase (no symbols list — cannot confirm implementation exists)
  • database.using_filters.not_in (no symbols list — cannot confirm implementation exists)
  • database.using_modifiers.order (no symbols list — cannot confirm implementation exists)
  • database.using_modifiers.limit (no symbols list — cannot confirm implementation exists)
  • database.using_modifiers.range (no symbols list — cannot confirm implementation exists)
  • database.using_modifiers.request_cancellation (no symbols list — cannot confirm implementation exists)
  • database.using_modifiers.relationship_embed (no symbols list — cannot confirm implementation exists)
  • database.configuration.request_timeout (no symbols list — cannot confirm implementation exists)
  • functions.invocation.region_selection (no symbols list — cannot confirm implementation exists)
  • functions.invocation.request_cancellation (no symbols list — cannot confirm implementation exists)
  • functions.invocation.timeout (no symbols list — cannot confirm implementation exists)
  • realtime.subscriptions.postgres_changes_filter (no symbols list — cannot confirm implementation exists)
  • realtime.subscriptions.private_channel (no symbols list — cannot confirm implementation exists)
  • realtime.subscriptions.broadcast_self (no symbols list — cannot confirm implementation exists)
  • realtime.subscriptions.broadcast_replay (no symbols list — cannot confirm implementation exists)
  • realtime.presence.presence_key (no symbols list — cannot confirm implementation exists)
  • realtime.configuration.heartbeat_interval (no symbols list — cannot confirm implementation exists)
  • storage.file_buckets.access_bucket (no symbols list — cannot confirm implementation exists)

These may have been renamed, removed, or never registered. Please update the capability matrix.
See: https://github.com/supabase/sdk/blob/main/packages/capability-matrix/docs/capability-matrix.md

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant