From 6b28e5e4dae7d90d02ca67eab0480c8111997fac Mon Sep 17 00:00:00 2001 From: Andy <119136210+AndyMik90@users.noreply.github.com> Date: Fri, 6 Feb 2026 23:50:33 +0100 Subject: [PATCH] auto-claude: 198-critical-oauth-token-revocation-causes-infinite-40 (#1747) * auto-claude: subtask-1-1 - Add errorCode propagation in reactiveTokenRefresh() * auto-claude: subtask-1-2 - Return null instead of revoked token for permanent errors in ensureValidToken() * auto-claude: subtask-1-3 - Clear credential cache on invalid_grant error in refreshOAuthToken() * auto-claude: subtask-1-4 - Clear revoked credentials on persistence failure (Bug #5) When token refresh succeeds but persistence to keychain fails, the old credentials in the keychain are now revoked server-side. This commit adds defensive cache clearing in both ensureValidToken() and reactiveTokenRefresh() to prevent serving revoked tokens from cache. On app restart, Bugs #3 and #4 fixes will handle the revoked credentials properly by returning null and clearing the cache, forcing re-authentication. Co-Authored-By: Claude Sonnet 4.5 * auto-claude: subtask-2-1 - Move authFailedProfiles marking before early return --------- Co-authored-by: Claude Sonnet 4.5 --- .../src/main/claude-profile/token-refresh.ts | 52 +++++++++++++++---- .../src/main/claude-profile/usage-monitor.ts | 17 +++--- 2 files changed, 52 insertions(+), 17 deletions(-) diff --git a/apps/frontend/src/main/claude-profile/token-refresh.ts b/apps/frontend/src/main/claude-profile/token-refresh.ts index ee31418c..f5d114b6 100644 --- a/apps/frontend/src/main/claude-profile/token-refresh.ts +++ b/apps/frontend/src/main/claude-profile/token-refresh.ts @@ -162,9 +162,13 @@ export function formatTimeRemaining(ms: number | null): string { * The new tokens must be stored immediately. * * @param refreshToken - The refresh token to use + * @param configDir - Optional config directory for the profile (used to clear cache on error) * @returns Result containing new tokens or error information */ -export async function refreshOAuthToken(refreshToken: string): Promise { +export async function refreshOAuthToken( + refreshToken: string, + configDir?: string +): Promise { const isDebug = process.env.DEBUG === 'true'; if (isDebug) { @@ -228,6 +232,11 @@ export async function refreshOAuthToken(refreshToken: string): Promise