convex auth user creation
For what I saw in some videos, the user should get created automatically when using convex auth. But in my case its not happening, does anyone know why it could be?
47 Replies
Thanks for posting in <#1088161997662724167>.
Reminder: If you have a Convex Pro account, use the Convex Dashboard to file support tickets.
- Provide context: What are you trying to achieve, what is the end-user interaction, what are you seeing? (full error message, command output, etc.)
- Use search.convex.dev to search Docs, Stack, and Discord all at once.
- Additionally, you can post your questions in the Convex Community's <#1228095053885476985> channel to receive a response from AI.
- Avoid tagging staff unless specifically instructed.
Thank you!
Debugging - Convex Auth
Authentication library for your Convex backend
It's hard to guess what's wrong without knowing how you set up Convex Auth, what your code looks like etc.
Is there a guide you followed to set up Convex Auth?
It's easy to miss some steps in https://labs.convex.dev/auth
Convex Auth - Convex Auth
Authentication library for your Convex backend
I faced the same error just know, my schema:
also hit another issue:
1. Type '(githubProfile: GitHubProfile) => { id: number; name: string | null; email: string | null; image: unknown; githubId: number; }' is not assignable to type 'ProfileCallback<GitHubProfile>'.
Type '{ id: number; name: string | null; email: string | null; image: unknown; githubId: number; }' is not assignable to type 'Awaitable<User>'.
Type '{ id: number; name: string | null; email: string | null; image: unknown; githubId: number; }' is not assignable to type 'User'.
Types of property 'id' are incompatible.
Type 'number' is not assignable to type 'string'. [2322]
in:
@Tom any idea?
I am confused as schema of authTable allows optional email:
@Karolus This validator error says email was
null
, which isn't allowed by v.optional(v.string())
. Only the property missing is allowed.
@Karolus do you see how to fix the second error? It says that what you're passing as the id
prop, githubProfile.id
, is a number, but id
expects a string.
So you should convert it into a stringregarding second issue, yes you can cast it
as unknown as string
, regarding first issue I am not really sure why I am not passing email, everything seems to work (redirect to github, authorization and redirect to my app)Don't do that,
as unknown as string
just changes the TypeScript type. It doesn't change the actual type
Try "" + githubProfile.id
, that's a way to actually convert it to a string
id: "" + githubProfile.id,
the type is actually provided by convex not mine
The type of
id
needs to be a string for Convex Auth. But you're passing a number, because githubProfile.id
is a number.
You should convert this number into a stringgot it, although even without returning values the problem with email remains:
The first problem, right?
yes
What user are you seeing this behavior for, your own?
I tried 2 accounts, for both actually
Do you have "share public email" disabled for these accounts?
in GitHub settings?
This sounds a bit like https://github.com/nextauthjs/next-auth/issues/374
probably
Are you using a GitHub OAuth app or a GitHub App?
Oh man, I would have never guessed that's where the problem is 😄
Should be OAuth Apps, right?
Yeah, apparently GitHub Apps work mostly but email may be null
That GitHub issue linked above has potential solutions for using a GitHub App instead, but we've never tested this
I've only tried GitHub OAuth apps
thanks, I will try with OAuth Apps then
confirmed, it worked! Thanks Tom
one last question, when using TanStack Router (not TanStack Start)
That would be best convention for auth?
or this:
These two should be the same, the implementation of
<AuthLoading>
and <Unauthenticated>
and <Authenticated>
is just using that useConvexAuth
hookI am asking because TanStack router recommends this type of solution:
I think these look good, let me know if you run into anything, I'd like to add a little guide somewhere for this
Maybe to https://github.com/TanStack/router/tree/main/examples/react or to https://docs.convex.dev/home somewhere
@Karolus mind if I use your screenshot to open an issue at https://github.com/get-convex/convex-auth/issues? will be easier to find if people search for it
sure
regarding convex auth with TanStack Router the closest I found was Clerk implementation, you can can auth state from context like so:
but convexClient seems to don't have auth property
Did you see this TanStack Start + Convex + Clerk example? https://github.com/get-convex/templates/tree/main/template-tanstack-start-clerk
oh and https://docs.convex.dev/client/react/tanstack-start/tanstack-start-with-clerk
I know you're not using Start but it has some of the context stuff
exactly this one, that's from I took above example
I am even passing convexClient to context
but I don't think it has auth state, right?
great i opened https://github.com/get-convex/convex-auth/issues/161 documenting the GitHub OAuth thing
ah I see
hm yeah, I see we need to do auth at that level somehow
right now the Convex Auth handshakes are being driven by that React component, but we need it in loaders (client and server) too
This has been on my list for a bit but because TanStack Start has take a while to get to 1.0 I haven't done it yet
So the goal would be similar to our Convex Auth Next.js middlware, that you can use a cookie or local storage to auth in beforeLoad like the clerk example does
and then you already know if you're authed ahead of time. But a bit tricky because there are two steps in Convex Auth, 1) getting the token and 2) actually sending it in over the WebSocket
so we'd also want to create the ConvexClient sooner, and at least send the token over the websocket before going further
I don't think we have to wait for the auth response, but we could via
convexClient.setAuth(getTokenFunction, onChange)
I don't think it matters in my particular case as I am wrapping this in Tauri app (which doesn't supports SSR) not sure how exactly beforeLoad works under the hood
that being said Clerk, Supabase examples uses beforeLoad for auth:
Supabase example
https://tanstack.com/start/latest/docs/framework/react/examples/start-supabase-basic
For Convex we probably need both, since Convex involves contantly refreshing the auth tokens while the user is on the page. But that works fine for the Clerk + Convex example, I just need to add some functionality for doing this with Convex Auth
we can do the wrap automatically too, that's what we do with the ConvexProvider
I see, so we would still need to wrap
Actually TanStack Router is client side router so beforeLoad also runs on client side from my understanding, so I think this approach could also work with Taurii technically. The only thing I am noticing in this solution: Loading authentication... is visible after every page refresh. So there is always this 1s delay before authentication state is determined.
<Outlet />
with <Authenticated />
to refresh the auth token?Actually TanStack Router is client side router so beforeLoad also runs on client side from my understanding, so I think this approach could also work with Taurii technically. The only thing I am noticing in this solution: Loading authentication... is visible after every page refresh. So there is always this 1s delay before authentication state is determined.
Can you do this part in a layout that's shared between all these paths?
oh wait ever refresh, or every navigation?
re refresh, yeha we'll need the beforeLoad solution for that I think
Great @Tom ,thanks for the help again. I am looking forward to the improvements 🙂
@Tom Actually, it happens on every navigation as well. I tested both
<Authenticated>
and useContextAuth
; they both result in this 1s delay to determine the auth state.
I would hope that for navigations, the AuthentticatedLayoutRoute would remain mounted so there's be no need to redo this
so sounds like we have some work to do, either an example of where to mount this differently or better, the beforeLoad approach
Yeah, seems like useConvexAuth() is at the component level, so it runs again for every navigation. I could probably store the auth state locally in Zustand and rely on it, but it's a bit of a stretch.
useConvexAuth()
has very little logic, it just grabs a context from an ancestor higher up the React element tree
so that higher-up thing is probably what's getting remounted, or otherwise causing a reset
https://github.com/get-convex/convex-js/blob/36d4a37e4b90ddcd4717e35572b8931331b7e23d/src/react/ConvexAuthState.tsx#L33-L58I see, unfortunately, it causes anything that was already mounted to disappear for 1-2 seconds, like AppSidebar in my example
Tomorrow, I will switch to Clerk for auth and verify if beforeLoad fixes the issue.
ah I see in docs when u use Clerk with Convex you still recommend to use
useConvexAuth
hook, so I will face same issue thereuseConvexAuth isn't the problem here, it returns whatever the auth state is from higher in the react tree
Yeah, got it. Just pointing that the same problem will existing no matter if it's Convex Auth or Clerk + Convex. It's a pity, I really enjoyed setting up the Auth with Convex. Super simple, good docs, but because of that issue, I don't think it's usable at this moment, at least not in Tanstack Router.
Try Clerk, I don't think it has this issue?
hm I will try, but are you sure? Clerk integration also relies on the same logic.: https://docs.convex.dev/auth/clerk#logged-in-and-logged-out-views
but Provider is different so maybe re-mounting won't happen
https://discord.com/channels/1019350475847499849/1335363286123675680
We followed up in the TanStack Discord, turns out these were full page navigations so the auth had to be brought up again. Things are working correctly with client-side navigations, so
<Link to={url}>
instead of <a>