Repository navigation
Conversation
A scheduled refetch runs refreshTokenLeewaySeconds before the token expires. When fetchToken returned null, refetchToken cleared auth at once on the open socket, so the server re-ran every query without an identity while the token was still valid. Keep the token and retry, waiting at most 10 s between attempts, until it has less than 2 s left; then clear auth as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
Author
|
Closing: we've heard you're working on something similar. Thanks! |
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.
This is created by my agent (running Opus 5.5), so please feel free to ignore if it does not make sense
Problem
scheduleTokenRefetchstartsrefetchToken()refreshTokenLeewaySecondsbefore the token expires. WhenfetchToken({ forceRefreshToken: true })returnsnull,refetchToken()callsclearAuth()straight away. That sendsAuthenticatewithtokenType: "None"over the open socket, so the server re-runs every active query without an identity, and auth-required queries all fail together. The token the server holds is still valid at that point.We see this in production with a React Native app, where token requests often fail for a few seconds on mobile networks. In one 3-hour window there were 39 such events, most failing more than 20 queries in the same second, roughly 300 a day. The app recovers once a later token request succeeds, but every subscribed query errors in between.
tryToReauthenticate()handles the samenulldifferently: it stops the socket before it fetches.Change
When a refetch returns
nulland the current token still has at least 2 s left (by itsexp), keep the token and schedule another refetch. Each retry waits half the remaining lifetime, capped at 10 s. Once the token has less than 2 s left, or there is no token or it can't be decoded, the behaviour is as before:clearAuth()andonAuthChange(false).waitingForScheduledRefetchstate, sosetConfig,stop()andtryToReauthenticate()cancel it like the normal scheduled refetch.tryToReauthenticate()takes over, as today.Open questions
null. ThesetAuthdocs describenullas "the token cannot be retrieved", with permanent revocation as an example. With this change, anullfrom a refetch before expiry signs the client out up to the leeway later rather than immediately. Explicit sign-out (clearAuth, orConvexProviderWithAuthseeingisAuthenticated: false) is unaffected. If you'd rather keepnullmeaning "sign out now", an alternative is a distinct signal for transient failures. That could be a new return value or option, or treating a thrownfetchTokenas transient: today a throw from the scheduled refetch is an unhandled rejection.refreshTokenLeewaySecondsinstead.Testing
src/browser/sync/authentication_manager.test.ts, using the realLocalSyncStatewith fake timers. A refetch that fails before expiry keeps the token and picks up a later fresh one. A refetch that keeps failing clears auth only in the last seconds before expiry. Both tests fail onmain. I know your main test suite isn't in this repository, so move or drop the file as you prefer.ConvexClientbuilt from this branch's source, withauthRefreshTokenLeewaySeconds: 840and afetchTokenthat returnsnullwhen forced. It kept its token, retried every 10 s, and had no query failures over 130 s. Onmain, both subscribed auth-required queries failed when the refetch ran.npm run typecheck,eslintandprettier -cpass on the changed files.🤖 Generated with Claude Code