Repository navigation
fix(auth): allow bounded retry after transient refresh failure on resume - #2769
Shoryamishra61 wants to merge 1 commit into
Conversation
In mobile / React Native environments, AppState transitions trigger supabase.auth.startAutoRefresh(). When an app initializes or foregrounds while offline, _callRefreshToken caches transient network failures in lastRefreshFailure for REFRESH_FAILURE_COOLDOWN_MS (60s). When connectivity is restored, subsequent foreground events or ticks within 60s hit this cooldown cache, returning the cached error without sending a single /token request. This change allows startAutoRefresh() to clear lastRefreshFailure on an intentional resume transition if the cached failure is retryable (isAuthRetryableFetchError), bounded by lastRecoveryAttemptAt so rapid fluttering or sustained offline resume events cannot cause a retry storm. Non-retryable errors (e.g. invalid tokens) and internal initialization remain strictly protected by the cooldown. Closes supabase#2767
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
📝 Summary
Priority: ➖ Normal Change: Bug fix · Severity of issue fixed: Medium Merge Risk: ⚪ Minimal · up to
|
|
Tested this on React Native (Expo SDK 58, RN 0.88, Hermes, iOS 26.5 simulator), A/B against v2.118.0. Stored session marked expired first, offline simulated in A. Offline refresh fails (8 attempts, 25.5 s) → network back →
B. Same, but the app returns to the foreground while still offline (AppState →
In B the offline |
🔍 Description
What changed?
_maybeRecoverOnStartAutoRefresh()toGoTrueClientwhich resetsthis.lastRefreshFailureupon an intentionalstartAutoRefresh()call on resume, provided:!this._isInitializing).isAuthRetryableFetchError).REFRESH_FAILURE_COOLDOWN_MS(tracked vialastRecoveryAttemptAt), preventing repeated resume events or offline fluttering from triggering a retry storm.lastRecoveryAttemptAtto0upon successful token rotation and session teardown (_removeSession).test/GoTrueClient.refreshRecovery.test.ts) covering 16 reproduction, cooldown, token rotation, concurrency, and security scenarios with offline mocks.Why was this change needed?
In mobile / React Native environments, applications respond to
AppStatetransitions (active) by callingsupabase.auth.startAutoRefresh(). When an app starts or attempts to refresh while offline,_callRefreshTokenrecords the failure inlastRefreshFailurewith a 60-second cooldown (REFRESH_FAILURE_COOLDOWN_MS). If network connectivity restores within that 60-second window, subsequent resume events and scheduled ticks immediately encounter the cooldown cache and return the cachedAuthRetryableFetchErrorwithout sending a single/tokenrequest. Users were left waiting up to 60 seconds before authentication could recover.Closes #2767
📸 Screenshots/Examples
🔄 Breaking changes
📋 Checklist
<type>(<scope>): <description>pnpm nx formatto ensure consistent code formatting📝 Additional notes
Root Cause
_callRefreshTokencaches both retryable and non-retryable failures inlastRefreshFailureforREFRESH_FAILURE_COOLDOWN_MS(60s) to prevent proactive refresh storms. While this protects against runaway retries during an outage, React Native has no browser-styleonlineevent to clear the cooldown; instead, mobile applications usestartAutoRefresh()on app foregrounding. Previously,startAutoRefresh()did not clearlastRefreshFailure, causing the client to return the cached failure for up to 60 seconds even after network was fully restored.Relationship to other PRs
REFRESH_FAILURE_COOLDOWN_MSand proactive session preservation. This PR strictly preserves that protection by retaining the 60s cooldown for serial calls and rate-limiting resume retries vialastRecoveryAttemptAt.window.addEventListener('online')reconnect handling. Becausewindowdoes not exist in React Native, PR fix(auth): fail token refresh fast when offline and resume on reconnect #2568 does not resolve issue auth-js: no public way to retry a refresh after a cached failure (REFRESH_FAILURE_COOLDOWN_MS), so mobile apps wait up to 60 s after the network comes back #2767 for mobile. Our change operates at the cross-platform lifecycle layer (startAutoRefresh) and complements fix(auth): fail token refresh fast when offline and resume on reconnect #2568 without conflict.Concurrency & Security Invariants
refreshingDeferredensures concurrent callers join the single in-flight network request._sessionRemovalEpochprevent session resurrection on concurrentsignOutor sign-in.invalid_grant) are never cleared on resume.