#Convex + WorkOS Authentication issues

4 messages · Page 1 of 1 (latest)

gritty currentBOT
#

Hi @slow hawk. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:

#

It appears you are experiencing a known issue where WorkOS successfully authenticates the user, but Convex fails to recognize that identity. Based on the knowledge sources, here are the most likely causes and solutions for this specific state:

1. Configuration of auth.config.ts

The most common cause for isAuthenticated remaining false even after a successful WorkOS login is a configuration mismatch in your Convex backend.

Example recommended config:

const clientId = process.env.WORKOS_CLIENT_ID;

export default {
  providers: [
    {
      type: "customJwt",
      issuer: "<https://api.workos.com/",>
      algorithm: "RS256",
      applicationID: clientId,
      jwks: `<https://api.workos.com/sso/jwks/${clientId}`,>
    },
    {
      type: "customJwt",
      issuer: `<https://api.workos.com/user_management/${clientId}`,>
      algorithm: "RS256",
      jwks: `<https://api.workos.com/sso/jwks/${clientId}`,>
      // applicationID removed here
    },
  ],
};
#

2. Missing aud (Audience) Claim

Convex requires the aud claim in the JWT to match your applicationID. By default, WorkOS JWTs might not include this.

  • Go to your WorkOS Dashboard.
  • Check your JWT configuration to ensure the audience claim is explicitly set to your WorkOS Client ID [Convex & WorkOS AuthKit].

3. Handling Race Conditions in the Auth Hook

If you are using a custom useAuth hook, you might be hitting a race condition where Convex tries to authenticate before the token is available. A recommended pattern to stabilize the auth state is to ensure isLoading correctly reflects both the user status and the token availability:

function useWorkosConvexAuth() {
  const { user, loading: isUserLoading } = useAuth();
  const { accessToken, loading: isTokenLoading } = useAccessToken();

  const isLoading = isUserLoading || isTokenLoading;
  const isAuthenticated = !!user && !!accessToken; // Ensure both exist

  const fetchAccessToken = useCallback(async () => {
    return accessToken ?? null;
  }, [accessToken]);

  return { isLoading, isAuthenticated, fetchAccessToken };
}

Adding || !accessToken to your loading logic can prevent a "flash" of unauthenticated state during the initial handshake [WorkOS Authkit as Custom Auth Integration with Convex].

#

4. Verification Steps

  • Run npx convex dev: Ensure your latest auth.config.ts changes are actually synced to the Convex cloud [Convex & WorkOS AuthKit].
  • Check Convex Logs: If ctx.auth.getUserIdentity() returns null inside a function despite the client being "authenticated," look for "Missing aud claim" or "Invalid issuer" errors in the Convex Dashboard logs [WorkOS Authkit as Custom Auth Integration with Convex].

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: