fix(clerk-js): prevent background token refresh from nuking sessions on mobile#8303
Draft
chriscanin wants to merge 3 commits intomainfrom
Draft
fix(clerk-js): prevent background token refresh from nuking sessions on mobile#8303chriscanin wants to merge 3 commits intomainfrom
chriscanin wants to merge 3 commits intomainfrom
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
🦋 Changeset detectedLatest commit: aacaa32 The changes in this PR will be included in the next version bump. This PR includes changesets to release 3 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
…on mobile On iOS, background thread throttling can starve the JS event loop for hours (e.g., overnight audio apps). When the SDK's background refresh timer eventually fires with stale credentials, the resulting 401 triggers handleUnauthenticated() which destroys the session even though it's still valid on the server. Adds an early return in #refreshTokenInBackground(), gated to headless/mobile runtimes only (Expo sets runtimeEnvironment to 'headless'). If the token has already expired when the refresh timer fires, bail out instead of sending a request with stale credentials. The next foreground getToken() call handles token acquisition through the normal path with proper retry logic.
ef85b82 to
ec92e8a
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes an issue where iOS background thread throttling causes unexpected session destruction in Expo/React Native apps.
The bug: On iOS, background audio apps (e.g., sleep/dream trackers) have their JS event loop starved for hours. When the SDK's background token refresh timer eventually fires, it sends a request with stale credentials → 401 →
handleUnauthenticated()cascades into destroying the session, even though it's still valid on the server (30-day lifetime). Users wake up to find they're signed out.The fix: A single early return in
#refreshTokenInBackground(), gated to headless/mobile runtimes only (Expo setsruntimeEnvironment: 'headless'). If the token has already expired when the refresh timer fires, the refresh cycle was starved by iOS background throttling — bail out instead of sending a request with stale credentials. The next foregroundgetToken()call handles token acquisition through the normal path with proper retry logic.Why this is safe
runtimeEnvironment === 'headless', which is only set by@clerk/expofor React Native. Web, Next.js, Remix, Chrome extension, etc. are completely unaffected._baseFetch,Token.create,handleUnauthenticated, or any other shared infrastructure. The change is entirely within the private#refreshTokenInBackground()method inSession.ts.getToken()call triggershandleUnauthenticated()through the normal path and signs the user out properly.Files changed
Session.ts#refreshTokenInBackground()when token is expired on headless runtimeSession.test.tsHow was this tested
/tokenswith 401, waits for background refresh timer (~43s), confirms session survives.getToken()still works after.Test plan
🤖 Generated with Claude Code