-
Notifications
You must be signed in to change notification settings - Fork 489
Description
Bug Description
In Electron mode, multiple 401 (Unauthorized) errors occur on app startup because API requests are made before initApiKey() completes fetching the API key from the Electron main process.
Reproduction Steps
- Run
npm run dev:electron(orOPEN_DEVTOOLS=true npm run dev:electron) - Open DevTools console
- Observe 401 errors for
/api/auth/token,/api/settings/status,/api/running-agents - WebSocket connection also fails with "HTTP Authentication failed"
Expected Behavior
All API requests should include the API key header and succeed without 401 errors.
Actual Behavior
GET /api/auth/token 401
GET /api/settings/status 401
GET /api/running-agents 401
WebSocket connection failed: HTTP Authentication failed; no valid credentials available
[HTTP Client] Using API key from Electron // This appears AFTER the 401s
Root Cause
initApiKey() is called inside a useEffect in RootLayoutContent, but other hooks (useSettingsMigration, useRunningAgents) call getHttpApiClient() which makes API requests before initApiKey() has completed.
The HttpApiClient constructor calls connectWebSocket() which calls fetchWsToken() - all before cachedApiKey is populated.
Affected Files
apps/ui/src/routes/__root.tsx(lines 82-120) -initApiKey()called in useEffectapps/ui/src/lib/http-api-client.ts(lines 75-95) -initApiKey()async functionapps/ui/src/lib/http-api-client.ts(lines 280-300) -connectWebSocket()usesgetApiKey()before it's readyapps/ui/src/hooks/use-settings-migration.ts(line 102) - callsgetHttpApiClient()early
Suggested Fix
Ensure initApiKey() completes before any component renders or makes API calls.
Option A: Block rendering until auth ready
// In __root.tsx or a wrapper component
const [authReady, setAuthReady] = useState(false);
useEffect(() => {
initApiKey().then(() => setAuthReady(true));
}, []);
if (!authReady) return <LoadingSpinner />;Option B: Lazy initialization in getHttpApiClient
// In http-api-client.ts
let clientInstance: HttpApiClient | null = null;
let initPromise: Promise<void> | null = null;
export const getHttpApiClient = async (): Promise<HttpApiClient> => {
if (!initPromise) {
initPromise = initApiKey();
}
await initPromise;
if (!clientInstance) {
clientInstance = new HttpApiClient();
}
return clientInstance;
};Regression
Introduced in PR #321 (protect-api-with-api-key), merged Dec 30, 2025.
Key commits:
d68de99- Added auth requirement to API endpoints469ee5f- AddedfetchWsToken()and hardened authd66259b- AddedverifySession()and modified auth flow