From 6794e4c234ada027d722bbc69b12afd3938fbd3f Mon Sep 17 00:00:00 2001 From: hsiegeln <37154749+hsiegeln@users.noreply.github.com> Date: Fri, 13 Mar 2026 22:09:46 +0100 Subject: [PATCH] Fix 401 race condition: wire getAccessToken at module level MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The auth store loads tokens from localStorage synchronously at import time, but configureAuth() was deferred to a useEffect — so the first API requests fired before the token getter was wired, causing 401s on hard refresh. Now getAccessToken reads from the store by default. Co-Authored-By: Claude Opus 4.6 (1M context) --- ui/src/api/client.ts | 8 +++++--- ui/src/auth/use-auth.ts | 3 +-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/ui/src/api/client.ts b/ui/src/api/client.ts index 3e9d003c..63779088 100644 --- a/ui/src/api/client.ts +++ b/ui/src/api/client.ts @@ -1,15 +1,17 @@ import createClient, { type Middleware } from 'openapi-fetch'; import type { paths } from './schema'; import { config } from '../config'; +import { useAuthStore } from '../auth/auth-store'; -let getAccessToken: () => string | null = () => null; +let getAccessToken: () => string | null = () => + useAuthStore.getState().accessToken; let onUnauthorized: () => void = () => {}; export function configureAuth(opts: { - getAccessToken: () => string | null; + getAccessToken?: () => string | null; onUnauthorized: () => void; }) { - getAccessToken = opts.getAccessToken; + if (opts.getAccessToken) getAccessToken = opts.getAccessToken; onUnauthorized = opts.onUnauthorized; } diff --git a/ui/src/auth/use-auth.ts b/ui/src/auth/use-auth.ts index 90331bfd..3d60ae3d 100644 --- a/ui/src/auth/use-auth.ts +++ b/ui/src/auth/use-auth.ts @@ -7,10 +7,9 @@ export function useAuth() { const { accessToken, isAuthenticated, refresh, logout } = useAuthStore(); const navigate = useNavigate(); - // Wire API client to auth store + // Wire onUnauthorized handler (needs navigate from router context) useEffect(() => { configureAuth({ - getAccessToken: () => useAuthStore.getState().accessToken, onUnauthorized: async () => { const ok = await useAuthStore.getState().refresh(); if (!ok) {