From de515f78a2b1e07acdcdb52d846b203b283777ae Mon Sep 17 00:00:00 2001 From: HolyCode User Date: Sat, 4 Apr 2026 08:00:23 +0000 Subject: [PATCH] fix: refresh Claude auth status after login flow --- server/routes/cli-auth.js | 43 +++++++++++++++---- .../settings/hooks/useSettingsController.ts | 32 +++++++++----- 2 files changed, 56 insertions(+), 19 deletions(-) diff --git a/server/routes/cli-auth.js b/server/routes/cli-auth.js index 78ffa30b4..b7a7faa9b 100644 --- a/server/routes/cli-auth.js +++ b/server/routes/cli-auth.js @@ -169,10 +169,29 @@ async function checkClaudeCredentials() { // Priority 2: Check ~/.claude/.credentials.json for OAuth tokens // This is the standard authentication method used by Claude CLI after running // 'claude /login' or 'claude setup-token' commands. + const notAuthenticatedResult = { + authenticated: false, + email: null, + method: null, + error: 'Claude CLI is not authenticated. Run claude /login or configure ANTHROPIC_API_KEY.' + }; + + const credPath = path.join(os.homedir(), '.claude', '.credentials.json'); + try { - const credPath = path.join(os.homedir(), '.claude', '.credentials.json'); const content = await fs.readFile(credPath, 'utf8'); - const creds = JSON.parse(content); + let creds; + + try { + creds = JSON.parse(content); + } catch { + return { + authenticated: false, + email: null, + method: null, + error: 'Claude credentials are unreadable. Run claude /login again.' + }; + } const oauth = creds.claudeAiOauth; if (oauth && oauth.accessToken) { @@ -185,18 +204,26 @@ async function checkClaudeCredentials() { method: 'credentials_file' }; } + + return { + authenticated: false, + email: null, + method: null, + error: 'Claude login has expired. Run claude /login again.' + }; } - return { - authenticated: false, - email: null, - method: null - }; + return notAuthenticatedResult; } catch (error) { + if (error?.code === 'ENOENT') { + return notAuthenticatedResult; + } + return { authenticated: false, email: null, - method: null + method: null, + error: 'Unable to read Claude credentials. Run claude /login again.' }; } } diff --git a/src/components/settings/hooks/useSettingsController.ts b/src/components/settings/hooks/useSettingsController.ts index 293cbceb5..332f4b1cc 100644 --- a/src/components/settings/hooks/useSettingsController.ts +++ b/src/components/settings/hooks/useSettingsController.ts @@ -268,36 +268,41 @@ export function useSettingsController({ isOpen, initialTab, projects, onClose }: setCodexAuthStatus(status); }, []); - const checkAuthStatus = useCallback(async (provider: AgentProvider) => { + const checkAuthStatus = useCallback(async (provider: AgentProvider): Promise => { try { const response = await authenticatedFetch(AUTH_STATUS_ENDPOINTS[provider]); if (!response.ok) { - setAuthStatusByProvider(provider, { + const status = { authenticated: false, email: null, loading: false, error: 'Failed to check authentication status', - }); - return; + }; + setAuthStatusByProvider(provider, status); + return status; } const data = await toResponseJson(response); - setAuthStatusByProvider(provider, { + const status = { authenticated: Boolean(data.authenticated), email: data.email || null, loading: false, error: data.error || null, method: data.method, - }); + }; + setAuthStatusByProvider(provider, status); + return status; } catch (error) { console.error(`Error checking ${provider} auth status:`, error); - setAuthStatusByProvider(provider, { + const status = { authenticated: false, email: null, loading: false, error: getErrorMessage(error), - }); + }; + setAuthStatusByProvider(provider, status); + return status; } }, [setAuthStatusByProvider]); @@ -729,12 +734,17 @@ export function useSettingsController({ isOpen, initialTab, projects, onClose }: }, [projects]); const handleLoginComplete = useCallback((exitCode: number) => { - if (exitCode !== 0 || !loginProvider) { + if (!loginProvider) { return; } - setSaveStatus('success'); - void checkAuthStatus(loginProvider); + void (async () => { + const authStatus = await checkAuthStatus(loginProvider); + + if (exitCode === 0) { + setSaveStatus(authStatus.authenticated ? 'success' : 'error'); + } + })(); }, [checkAuthStatus, loginProvider]); const saveSettings = useCallback(async () => {