( failedAccessToken: string, )
| 1371 | } |
| 1372 | |
| 1373 | async function handleOAuth401ErrorImpl( |
| 1374 | failedAccessToken: string, |
| 1375 | ): Promise<boolean> { |
| 1376 | // Clear caches and re-read from keychain (async — sync read blocks ~100ms/call) |
| 1377 | clearOAuthTokenCache() |
| 1378 | const currentTokens = await getClaudeAIOAuthTokensAsync() |
| 1379 | |
| 1380 | if (!currentTokens?.refreshToken) { |
| 1381 | return false |
| 1382 | } |
| 1383 | |
| 1384 | // If keychain has a different token, another tab already refreshed - use it |
| 1385 | if (currentTokens.accessToken !== failedAccessToken) { |
| 1386 | logEvent('tengu_oauth_401_recovered_from_keychain', {}) |
| 1387 | return true |
| 1388 | } |
| 1389 | |
| 1390 | // Same token that failed - force refresh, bypassing local expiration check |
| 1391 | return checkAndRefreshOAuthTokenIfNeeded(0, true) |
| 1392 | } |
| 1393 | |
| 1394 | /** |
| 1395 | * Reads OAuth tokens asynchronously, avoiding blocking keychain reads. |
no test coverage detected