( failedAccessToken: string, )
| 1428 | } |
| 1429 | |
| 1430 | async function handleOAuth401ErrorImpl( |
| 1431 | failedAccessToken: string, |
| 1432 | ): Promise<boolean> { |
| 1433 | // Clear caches and re-read from keychain (async — sync read blocks ~100ms/call) |
| 1434 | clearOAuthTokenCache() |
| 1435 | const currentTokens = await getClaudeAIOAuthTokensAsync() |
| 1436 | |
| 1437 | if (!currentTokens?.refreshToken) { |
| 1438 | return false |
| 1439 | } |
| 1440 | |
| 1441 | // If keychain has a different token, another tab already refreshed - use it |
| 1442 | if (currentTokens.accessToken !== failedAccessToken) { |
| 1443 | logEvent('tengu_oauth_401_recovered_from_keychain', {}) |
| 1444 | return true |
| 1445 | } |
| 1446 | |
| 1447 | // Same token that failed - force refresh, bypassing local expiration check |
| 1448 | return checkAndRefreshOAuthTokenIfNeeded(0, true) |
| 1449 | } |
| 1450 | |
| 1451 | /** |
| 1452 | * Reads OAuth tokens asynchronously, avoiding blocking keychain reads. |
no test coverage detected