-
Notifications
You must be signed in to change notification settings - Fork 3
Fix AuthKit + Convex race condition on laptop wake #17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Resolves intermittent authentication failures after laptop sleep/wake that caused users to be logged out or redirected to sign-in. ## Root Cause Two independent failures triggered by network instability during wake: 1. Token refresh race: Convex reconnects before network is ready → getAccessToken() throws → returns null → unmounts components 2. Visibility handler: AuthKit detects "Failed to fetch" → reloads page → middleware redirects to sign-in ## Solution - Add onSessionExpired handler to prevent page reload on network errors - Capture access token with ref to preserve it across state changes - Fall back to cached token when getAccessToken() throws - Let AuthKit's tokenStore handle background retries This allows graceful degradation: Convex stays authenticated using valid cached tokens while AuthKit retries refresh in the background. Tested with 1-minute token TTL and 3+ minute sleep cycles.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Were you able to reproduce the issue without this change, for evidence this fixes it? I'd love to know what's happening and to figure out which of these changes we need
|
|
||
| return ( | ||
| <AuthKitProvider> | ||
| <AuthKitProvider onSessionExpired={noop}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does this do, disable some default onSessionExpired behavior? a comment would be helpful
| const isAuthenticated = !!user; | ||
|
|
||
| // Keep ref updated with latest token | ||
| useEffect(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why update the accessTokenRef in an effect, can you just assign to it when it updates?
| if (isTokenValid(cachedToken)) { | ||
| console.log('[Convex Auth] Using cached token during network issues'); | ||
| return cachedToken!; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like the main change here is to try to return the last token on error, does the isTokenValid help at all? The Convex client treats an invalid client roughly like a null, both will clear the auth, so I'd think it'd be fine to skip the isTokenValid and keep it simple.
What kinds of errors are we seeing, is it a network error talking to WorkOS, should we retry it?
|
|
||
| try { | ||
| if (forceRefreshToken) { | ||
| return (await refresh()) ?? null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is refresh() not the right way to refresh?
|
Any updates regarding this PR? Without following the template, developing this provider would not be very straightforward (at least for me). There is an outdated version still in the convex docs, which needs an update as well (assuming this version in the template is correct/better?). |
Summary
Fixes intermittent authentication failures after laptop sleep/wake that caused users to be logged out or redirected to sign-in.
Root Cause
Two independent failures triggered by network instability during wake:
Token refresh race: Convex websocket reconnects before network is ready →
getAccessToken()throws → returnsnull→ Convex unmounts authenticated componentsVisibility handler reload: AuthKit's visibility change handler detects "Failed to fetch" → triggers
window.location.reload()→ middleware redirects to sign-inSolution
Three changes to
ConvexClientProvider.tsx:onSessionExpiredhandler - Prevents AuthKit from reloading the page on network errorsgetAccessToken()throws, falls back to cached token if still validThis allows graceful degradation: Convex stays authenticated using valid cached tokens while AuthKit's tokenStore retries refresh in the background.
Testing