#intermitent failure Clerk: `const identity = await ctx.auth.getUserIdentity();`

92 messages · Page 1 of 1 (latest)

fresh epoch
#

Problem: the app works when page loads but if I reload it, the identity is null.

In development I have two apps that share the same convex dev in the same monorepo. I run them one a a time in localhost:3000, so when i use one app i don't run the other one.

This is the function that is throwing when getUserIdentity. It works fine on the first call, but fails after that.

// convex/page.ts
export const getPage = query({
  args: { customerId: v.optional(v.id("bz_customers")) },
  handler: async (ctx, { customerId }) => {
    const identity = await ctx.auth.getUserIdentity(); // works the first time.
    if (!identity) throw new Error("Identidad no encontrada"); // throws on subsequent calls (reload of page or changing the args values from the react component hook useQuery)

   //...etc

Dependency:
"convex": "^1.11.0",

The auth is managed with Clerk. I set a JWT template for each app, with the same applicationID: "convex"

// auth.config.js
// Both env variables are set in dashboard.convex.dev
export default {
  providers: [
    { applicationID: "convex", domain: process.env.CLERK_JWT_ISSUER_DOMAIN }, // fentex.com
    {
      applicationID: "convex",
      domain: process.env.BREZZA_CLERK_JWT_ISSUER_DOMAIN, // brezza.com
    }, 
  ],
};

The other app works fine. it was the first one that i set up. The failure happens on the second app that I added.

The apps are in different url domains.

I wonder if it is a dirty state in the auth system.

Any idea how can I debug this?

fresh epoch
#
"use client";

import { esES } from "@clerk/localizations";
import { ConvexReactClient } from "convex/react";
import { ConvexProviderWithClerk } from "convex/react-clerk";
import { ClerkProvider, useAuth } from "@clerk/nextjs";
const convex = new ConvexReactClient(process.env.NEXT_PUBLIC_CONVEX_URL);

export default function ConvexClientProvider({ children }) {
  return (
    <ClerkProvider
      localization={esES}
      publishableKey={process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY}
    >
      <ConvexProviderWithClerk client={convex} useAuth={useAuth}>
        {children}
      </ConvexProviderWithClerk>
    </ClerkProvider>
  );
}
#

using Next.js app router

#

layout.js

#

export default function RootLayout({ children }) {
  return (
    <>
      {process.env.NEXT_PUBLIC_NODE_ENV === "production" ? (
        <LogRocketComponent />
      ) : null}

      <ConvexClientProvider>
        <html lang="es-MX" className="antialiased">
          <body
            className={`bg-stone-50 dark:bg-stone-900 dark:text-stone-200 print:bg-white ${inter.className} `}
          >
            {children}
            <Toaster richColors />
          </body>
        </html>
      </ConvexClientProvider>
    </>
  );
}
boreal isle
#

I have also been facing this issue and have been using a workaround (probably not the best one) and would like someone to comment on this if they have a nice solution 😃

frosty gorge
#

I think I encounter the same error

#

Somehow if I delete all cookies and the localstorage and try to signin again everything works again for 1 time

#

this is especially painful if you do something like this: signup -> singout -> singup with new account

frosty gorge
fresh epoch
#

I wonder if the applicationID has to be unique

#

in auth.config.js

frosty gorge
#

What do you mean excactly?

fresh epoch
#

so probably in the second applicationID it should be different so they are unique

#

but if i change the value it won't work at all

frosty gorge
#

You also have to change the name in the Clerk Dashboard

frosty gorge
#

Just to make sure that I understand everything correctly

fresh epoch
frosty gorge
fresh epoch
frosty gorge
fresh epoch
#

another different thing in the app that is failing is that instead of a users table i'm using bz_users

#

but i don't think that has anything to do with identity

frosty gorge
frosty gorge
fresh epoch
#

@frosty gorge are you using app router with RSC pages?

grand violet
#

I’m not sure what could be causing this.

To change the applicationId, change the aud field in the Clerk JWT token template. That’s where the value “coomes from”.

The other things i would try:

  1. Maybe the Clerk config has an issue. Create a new one.
  2. Run the apps on different ports.
frosty gorge
#

But is this limited to app router?

fresh epoch
#

seems like if the auth cookie is lost

brazen light
#

Hello, is this issue supposed to be pinned in Support channel instead of Convex Search? @grand violet

frosty gorge
fresh epoch
fresh epoch
fresh epoch
#

i have a bunch working well.. it is just this one that is failing

frosty gorge
fresh epoch
#

i also use pnpm

frosty gorge
#

also does it work with the pages router?

fresh epoch
#

but my other projects work fine with pnpm

frosty gorge
fresh epoch
frosty gorge
#

I can also write a new minimal repro for the pages router

fresh epoch
#

i'm rolling back to clerk 4.29.9

#

that didnt help

fresh epoch
#

I noticed in the network tab that when it loads a route that works it shows _rsc in the payload.

grand violet
#

Can you share the useQuery callsite? Do you have the component inside Authenticated? Have you checked the auth debugging guide?

frosty gorge
#

The debugging site says that something is misconfigure but it works for one time and and after that not anymore so I think it has to be a bug in Convex at this point

#

Michal. Can you validate that my reproduction has this error and that my reproduction is correctly configured?

fresh epoch
fresh epoch
frosty gorge
fresh epoch
#

I also noticed that the other app that i thought it was fine it also fails with identity on queries

#

ok, I just realized that on my other apps i was only using const identity = await auth.getUserIdentity(); on mutations... so i had a false sense of success.

frosty gorge
#

The other question is: this seems to be a general issue with convex + clerk, but why aren't there much others having this issue?

frosty gorge
royal condor
#

To echo what Michal said earlier -- a really common cause of getUserIdentity being null is calling the function without gating on the Convex isAuthenticated or rendering within the Authenticated component. It's not enough to check using the clerk hooks (between steps 4 and 7 in https://docs.convex.dev/auth/clerk#under-the-hood is where clerk auth is set but hasn't been propagated to convex yet)

Looking at the callsites (the useQuery and useMutation calls) in your client code will probably be the most helpful in terms of debugging (and where we're checking

Concretely, I took a look at https://github.com/FleetAdmiralJakob/minimal-reproduction-convex-clerk/blob/bc2eab8e0f117babe299bae3cf7210f6661bdb3d/src/app/page.tsx#L33C10-L33C23 and it looks like we're calling the mutation without checking that isAuthenticated is true? Instead of calling the mutation immediately, could you store state that a sign up was created and have a separate useEffect that calls the mutation if there was a sign up and isAuthenticated is set?

GitHub

Contribute to FleetAdmiralJakob/minimal-reproduction-convex-clerk development by creating an account on GitHub.

Clerk is an authentication platform providing login via

fresh epoch
royal condor
#

Every component where the query / mutation expects getUserIdentity to be populated. Other options are to conditionally call your functions (e.g. useQuery(api.my.query, isAuthenticated ? args : "skip")) or handling getUserIdentity being null in the functions (returning a placeholder value until auth has propagated through).

#

I'm not an expert on auth with Convex, and the approach you take depends on the kind of app you're building. For the personal projects I've built, I've usually just wrapped the root of my app (or a few key pages) with Authenticated and had all my functions assume getUserIdentity would be set

fresh epoch
royal condor
#

Yeah I agree we can better document this (I believe we already have some stuff in the works here)

fresh epoch
#

yeah it's an important point for safety. i do like better the approach from clerk that assumes everything must be authenticated and you have to manually declare public routes. This is a recommended best practice in app security. So it would be great at the auth.config.js to toggle if you want full auth expectation and whitelist individually the functions that dont need auth

normal igloo
#

@fresh epoch is this all set now? Was the main difference the fact that it was Next.js and a combo of authentication passes w/ intermediate state where convex wasn't authenticated yet, maybe b/c of SSR, solved by wrapping more things in <Authenticated>?

frosty gorge
fresh epoch
fresh epoch
normal igloo
fresh epoch
#

so seems that isAuthenticated is more in sync with convex than Authenticated

#

in my opinion the user shouldn't have to skip useQuery depending on isAuthenticated. In that case i might as well use the useUser hook and pass the user data as an arg to query

normal igloo
#

yeah we need to make this cleaner. One thing about using useUser is that you can't necessarily trust user data sent as arguments. A client could send up user data from a different user.

grand violet
#

@fresh epoch Authenticated just calls useConvexAuth under the hood, so it would be very surprising if it behaved differently. If you can get a repro of that issue that would be valuable.

boreal isle
#

There were some really good points made in this conversation and helped me decide the next steps. Thank you all!

fresh epoch
#

interesting that in my setup i don't need to use isAuthenticated or Authenticated for mutations.

midnight forge
#

I have the same problem…! will be resolving today based on the comments so far! Thank you all 🙏

grand violet
#

interesting that in my setup i don't need to use isAuthenticated or Authenticated for mutations.
Mutations usually happen based on some user action, and by that time the auth has been setup.

The Authenticated component really just makes the client "wait" before subscribing to queries in its children (by not rendering its children).

boreal isle
#

Components with queries and mutations wrapped with <Authenticated/> and a custom skeleton wrapped in <AuthLoading/> has been working great for me so far!

grand violet
#

@fresh epoch @boreal isle @midnight forge I'm interested whether you read through the Clerk docs first, or looked at the "example" repo linked from the top of the docs, or some other template? Trying to figure out how to guide folks better to the correct setup.

fresh epoch