Files
nuzlocke-tracker/.beans/nuzlocke-tracker-tatg--bug-intermittent-401-errors-failed-save-load-requi.md
Julian Tabel c5959cfd14
All checks were successful
CI / backend-tests (pull_request) Successful in 33s
CI / frontend-tests (pull_request) Successful in 33s
chore: mark ES256 JWT support bean as completed
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 11:53:13 +01:00

2.2 KiB

title, status, type, priority, created_at, updated_at
title status type priority created_at updated_at
Bug: Intermittent 401 errors / failed save-load requiring page reload completed bug high 2026-03-21T21:50:48Z 2026-03-22T09:44:54Z

Problem

During gameplay, the app intermittently fails to load or save data. A page reload fixes the issue. Likely caused by expired Supabase JWT tokens not being refreshed automatically before API calls.

Current Implementation

  • Auth uses Supabase JWTs verified with HS256 (backend/auth.py:39-44)
  • Frontend gets token via supabase.auth.getSession() in client.ts:16-21
  • getAuthHeaders() returns the cached session token without checking expiry
  • When the token expires between interactions, API calls return 401
  • Page reload triggers a fresh getSession() which refreshes the token

Root Cause Analysis

getSession() returns the cached token. If it's expired, the frontend sends an expired JWT to the backend, which rejects it with 401. The frontend doesn't call refreshSession() or handle token refresh before API calls.

Proposed Fix

  • Add token refresh logic before API calls (check expiry, call refreshSession() if needed)
  • Add 401 response interceptor that automatically refreshes token and retries the request
  • Verify Supabase client autoRefreshToken option is enabled
  • Test with short-lived tokens to confirm refresh works (manual verification needed)
  • Check if there's a race condition when multiple API calls trigger refresh simultaneously (supabase-js v2 handles this with internal mutex)

Summary of Changes

  • supabase.ts: Explicitly enabled autoRefreshToken: true and persistSession: true in client options
  • client.ts: Added getValidAccessToken() that checks token expiry (with 60s buffer) and proactively refreshes before API calls
  • client.ts: Added 401 interceptor in request() that retries once with a fresh token

The fix addresses the root cause by:

  1. Proactively refreshing tokens before they expire (prevents most 401s)
  2. Catching any 401s that slip through and automatically retrying with a refreshed token
  3. Ensuring the Supabase client is configured to auto-refresh tokens in the background