#?
1 messages · Page 1 of 1 (latest)
Hi @prime scarab. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:
This is a known issue area with Convex + Next.js + WorkOS; what you’re seeing is almost certainly related to how auth state and tokens refresh while your app has been idle.
From the threads:
- When WorkOS refreshes its access token (default every ~5 minutes), the app can briefly go through a
Loading/Unauthenticatedstate, which unmounts components and then remounts them once Convex has a valid token again. This can look like a brief white screen or “flash” when you come back after being idle and navigate. [WorkOS + Convex thread] - There are also reports of users getting logged out or seeing unauthenticated errors or UI flashes when returning after a laptop has been asleep or a tab has been idle, again tied to token refresh and re‑auth. [WorkOS + Convex thread]
- Convex’s client will proactively ask for a fresh token ~10 seconds before expiry, but WorkOS’s hooks sometimes report a transient “loading” or “unauthenticated” state during that refresh, which causes the UI to blank out briefly. [WorkOS + Convex thread]
So the white screen after idling + page switch is almost certainly:
- Your WorkOS hooks briefly say “loading” / “unauthenticated” while refreshing the token.
- Your layout or route guards unmount the authenticated tree (or show a loading state).
- Once the new token is validated by Convex, everything remounts.
Mitigations discussed in the threads (not full fixes, but help):
- In your
useAuthFromAuthKit/useAuthwrapper passed toConvexProviderWithAuth, avoid flipping to a “loading” or “unauthenticated” state during token refresh; e.g. cache a previous “authenticated” state and keep reportingisAuthenticated: truewhile WorkOS is just refreshing. [WorkOS + Convex hook examples] - Prefer using
getAccessToken()fromuseAccessToken(guaranteed fresh) instead of relying on a possibly staleaccessTokenvalue, and havefetchAccessTokenalways call that, returningnullonly on real errors. [WorkOS + Convex getAccessToken fix]
However, the knowledge sources also say this behavior (flash / brief unauth) is still being actively worked on and not fully solved in all setups yet, especially with Next.js App Router. [WorkOS + Convex status]
If you want more concrete help, the next step would be:
- Share your Convex client/provider + WorkOS integration code and layout structure (especially anything that conditionally renders based on
loading/isAuthenticated), and - Try to reproduce with a very short WorkOS access token lifetime (e.g. 1 minute) so you can see the pattern more clearly, as suggested in the threads. [WorkOS token duration debugging]
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
@prime scarab Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@edgy lava this is what im using:
'use client';
import { ReactNode, useCallback, useRef, useEffect } from 'react';
import { ConvexReactClient } from 'convex/react';
import { ConvexProviderWithAuth } from 'convex/react';
import { AuthKitProvider, useAuth, useAccessToken } from '@workos-inc/authkit-nextjs/components';
const convex = new ConvexReactClient(process.env.NEXT_PUBLIC_CONVEX_URL!);
export function ConvexClientProvider({ children }: { children: ReactNode }) {
return (
<AuthKitProvider>
<ConvexProviderWithAuth client={convex} useAuth={useAuthFromAuthKit}>
{children}
</ConvexProviderWithAuth>
</AuthKitProvider>
);
}
function useAuthFromAuthKit() {
const { user, loading: isLoading } = useAuth();
const { accessToken, loading: tokenLoading, error: tokenError } = useAccessToken();
const loading = (isLoading ?? false) || (tokenLoading ?? false);
const authenticated = !!user && !!accessToken && !loading;
const stableAccessToken = useRef<string | null>(null);
useEffect(() => {
if (accessToken && !tokenError) {
stableAccessToken.current = accessToken;
}
}, [accessToken, tokenError]);
const fetchAccessToken = useCallback(async () => {
if (stableAccessToken.current && !tokenError) {
return stableAccessToken.current;
}
return null;
}, [tokenError]);
return {
isLoading: loading,
isAuthenticated: authenticated,
fetchAccessToken,
};
}
Let me check the knowledge base for you again. One moment! :books:
Your white screen is very likely coming from how isLoading / isAuthenticated are computed in your useAuthFromAuthKit hook during token refreshes.
From the Discord thread, people saw the same behavior (brief unauth / loading flashes, components unmounting, white screen) and fixed it by:
- Not treating token refresh as “loading” for Convex.
- Using
getAccessToken()instead of the possibly staleaccessTokenvalue. [WorkOS getAccessToken fix]
Your current logic:
const loading = (isLoading ?? false) || (tokenLoading ?? false);
const authenticated = !!user && !!accessToken && !loading;
So when WorkOS is refreshing:
tokenLoadingcan betrueloadingbecomestrueauthenticatedbecomesfalse- Convex sees
isAuthenticated: falseand/orisLoading: true, and your<Authenticated>/<AuthLoading>UI likely unmounts → white screen.
Recommended change
Based on the working patterns in the thread, adjust your hook to:
- Consider the user authenticated as soon as
userexists, even while the token is refreshing. - Use
getAccessToken()to always get a fresh token for Convex. - Only report
isLoadingduring the initial load, not during refreshes.
A minimal version aligned with what others reported fixing their “idle → white screen” issue is:
function useAuthFromAuthKit() {
const { user, loading: isUserLoading } = useAuth();
const {
getAccessToken,
loading: isTokenLoading,
error: tokenError,
} = useAccessToken();
const isLoading = (isUserLoading ?? false) || (isTokenLoading ?? false);
const isAuthenticated = !!user;
const fetchAccessToken = useCallback(async () => {
if (tokenError) return null;
const token = await getAccessToken();
return token ?? null;
}, [getAccessToken, tokenError]);
return {
isLoading,
isAuthenticated,
fetchAccessToken,
};
}
This pattern (using `getAccessToken` and not tying `isAuthenticated` to `accessToken`/`tokenLoading`) is exactly what another user used to stop unauthenticated flashes after idle / refresh. [[WorkOS getAccessToken fix](<https://discord.com/channels/1019350475847499849/1202520608672317471>)]
If you still see a flash, the thread also suggests an extra refinement: track an “initially loaded” flag so that `isLoading` is only `true` on first load, not during background refreshes. [[WorkOS loading-state tweaks](<https://discord.com/channels/1019350475847499849/1202520608672317471>)]
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------
@prime scarab Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@edgy lava i dont mind hte flash, is just that when it happens my page stays blank
Let me check the knowledge base for you again. One moment! :books:
The knowledge sources don’t show a case where the page stays blank permanently; they only describe brief flashes / rerenders during token refresh. So I can’t say with certainty what’s causing a persistent white screen in your specific app.
What we do know from the WorkOS + Convex threads:
- The Convex client will keep trying to authenticate and reconnect when tokens expire; even when there’s a refresh race, queries eventually resume and the UI comes back. [WorkOS + Convex refresh behavior]
- The “blank for a split second” issue was fixed for some people by changing the
useAuthFromAuthKitwrapper (like thegetAccessTokenversion I showed) and by tightening the loading condition (e.g. including!accessTokenin the loading boolean). [WorkOS loading-state tweaks]
If your page stays blank, that usually means your UI logic is never leaving a “loading” or “unauthenticated” branch. The docs explicitly recommend:
- Use Convex’s
<Authenticated>,<Unauthenticated>,<AuthLoading>anduseConvexAuth()to drive UI, not WorkOS’suseAuth()directly. [Convex + AuthKit docs]
So the most likely causes (based on the sources) are:
- Your
useAuthFromAuthKitis returningisLoading: trueorisAuthenticated: falseindefinitely after a refresh edge case. - Your layout / routes render nothing (or only a loading screen) when
isLoadingis true orisAuthenticatedis false, and that state never flips back.
To debug concretely:
-
Log what
useAuthFromAuthKitreturns over time:console.log('auth state', { isLoading, isAuthenticated }); -
Also log
useConvexAuth()in a simple component:
import { useConvexAuth } from 'convex/react';
function DebugAuth() {
const { isAuthenticated, isLoading } = useConvexAuth();
console.log('convex auth', { isAuthenticated, isLoading });
return null;
}
If useConvexAuth() does eventually show isAuthenticated: true but your page is still blank, the issue is in your own conditional rendering (e.g. a guard that never re-renders). If useConvexAuth() stays unauthenticated forever after idle, that’s closer to the race/refresh issues being discussed and would be worth turning into a minimal repro and filing on the WorkOS template repos, as suggested in the thread. [WorkOS template issues]