MCPcopy
hub / github.com/claude-code-best/claude-code / recoverFromAuthFailure

Function recoverFromAuthFailure

src/bridge/remoteBridgeCore.ts:557–617  ·  view source on GitHub ↗
()

Source from the content-addressed store, hash-verified

555
556 // ── 8. 401 recovery (OAuth refresh + rebuild) ───────────────────────────
557 async function recoverFromAuthFailure(): Promise<void> {
558 // setOnClose already guards `!authRecoveryInFlight` but that check and
559 // this set must be atomic against onRefresh — claim synchronously before
560 // any await. Laptop wake fires both paths ~simultaneously.
561 if (authRecoveryInFlight) return
562 authRecoveryInFlight = true
563 onStateChange?.('reconnecting', 'JWT expired — refreshing')
564 logForDebugging('[remote-bridge] 401 on SSE — attempting JWT refresh')
565 try {
566 // Unconditionally try OAuth refresh — getAccessToken() returns expired
567 // tokens as non-null strings, so !oauthToken doesn't catch expiry.
568 // Pass the stale token so handleOAuth401Error's keychain-comparison
569 // can detect if another tab already refreshed.
570 const stale = getAccessToken()
571 if (onAuth401) await onAuth401(stale ?? '')
572 const oauthToken = getAccessToken() ?? stale
573 if (!oauthToken || tornDown) {
574 if (!tornDown) {
575 onStateChange?.('failed', 'JWT refresh failed: no OAuth token')
576 }
577 return
578 }
579
580 const fresh = await withRetry(
581 () =>
582 fetchRemoteCredentials(
583 sessionId,
584 baseUrl,
585 oauthToken,
586 cfg.http_timeout_ms,
587 ),
588 'fetchRemoteCredentials (recovery)',
589 cfg,
590 )
591 if (!fresh || tornDown) {
592 if (!tornDown) {
593 onStateChange?.('failed', 'JWT refresh failed after 401')
594 }
595 return
596 }
597 // If 401 interrupted the initial flush, writeBatch may have silently
598 // no-op'd on the closed uploader (ccr.close() ran in the SSE wrapper
599 // before our setOnClose callback). Reset so the new onConnect re-flushes.
600 // (v1 scopes initialFlushDone inside the per-transport closure at
601 // replBridge.ts:1027 so it resets naturally; v2 has it at outer scope.)
602 initialFlushDone = false
603 await rebuildTransport(fresh, 'auth_401_recovery')
604 logForDebugging('[remote-bridge] Transport rebuilt after 401')
605 } catch (err) {
606 logForDebugging(
607 `[remote-bridge] 401 recovery failed: ${errorMessage(err)}`,
608 { level: 'error' },
609 )
610 logForDiagnosticsNoPII('error', 'bridge_repl_v2_jwt_refresh_failed')
611 if (!tornDown) {
612 onStateChange?.('failed', `JWT refresh failed: ${errorMessage(err)}`)
613 }
614 } finally {

Callers 1

wireTransportCallbacksFunction · 0.85

Calls 8

onStateChangeFunction · 0.85
getAccessTokenFunction · 0.85
rebuildTransportFunction · 0.85
logForDiagnosticsNoPIIFunction · 0.85
withRetryFunction · 0.70
fetchRemoteCredentialsFunction · 0.70
logForDebuggingFunction · 0.50
errorMessageFunction · 0.50

Tested by

no test coverage detected