Devben
Devben10mo ago

Help using convex with clerk

Note: am new to convex. I follow the document on how to use clerk with convex I successfully see the user info in clerk but not in convex and I even try to debug using clerk debug method still not working despite the fact that I connect my front with convex using npx convex dev.
46 Replies
Devben
DevbenOP10mo ago
Code: this is for user.ts in convex folder: import { mutation } from "./_generated/server"; export const store = mutation({ args: {}, handler: async (ctx) => { const identity = await ctx.auth.getUserIdentity(); console.log("server identity", await ctx.auth.getUserIdentity()); if (!identity) { throw new Error("Called storeUser without authentication present"); } // Check if we've already stored this identity before. const user = await ctx.db .query("users") .filter((q) => q.eq(q.field('tokenIdentifer'), identity.tokenIdentifier)) .unique(); if (user !== null) { // If we've seen this identity before but the name has changed, patch the value. if (user.name !== identity.name) { await ctx.db.patch(user._id, { name: identity.name }); } return user._id; } // If it's a new identity, create a new User. return await ctx.db.insert("users", { name: identity.name!, tokenIdentifier: identity.tokenIdentifier, }); }, }); This is the useStoreUser hook: import { useUser } from "@clerk/clerk-react"; import { useConvexAuth } from "convex/react"; import { useEffect, useState } from "react"; import { useMutation } from "convex/react"; import { api } from "../convex/_generated/api"; import { Id } from "../convex/_generated/dataModel"; export default function useStoreUserEffect() { const { isAuthenticated } = useConvexAuth(); const { user } = useUser(); // When this state is set we know the server // has stored the user. const [userId, setUserId] = useState<Id<"users"> | null>(null); const storeUser = useMutation(api.user.store); // Call the storeUser mutation function to store // the current user in the users table and return the Id value. useEffect(() => { // If the user is not logged in don't do anything if (!isAuthenticated) { return; } // Store the user in the database. // Recall that storeUser gets the user information via the auth // object on the server. You don't need to pass anything manually here. async function createUser() { const id = await storeUser(); setUserId(id); } createUser(); return () => setUserId(null); // Make sure the effect reruns if the user logs in with // a different identity }, [isAuthenticated, storeUser, user?.id]); return userId; } How I handle the clerk login/signup import { cn } from "@/lib/utils"; import "./btn.css"; import React from "react"; import { useSignIn } from "@clerk/nextjs"; // function SSOCallback() { // return <AuthenticateWithRedirectCallback afterSignInUrl={'/verifications'}/>; // } export const CustomBtn = ({ children, className, }: { children?: any; className?: any; }) => { const { signIn } = useSignIn(); const handleGitHubSignUp = async () => { await signIn?.authenticateWithRedirect({ strategy: "oauth_github", redirectUrl: "/", redirectUrlComplete: "/", }); console.log("Added successfully"); }; return ( <main> <button className={cn("btn", className)} onClick={handleGitHubSignUp}> {children} </button> </main> ); }; I would be happy to provide any code that may help in resolving this
jamwt
jamwt10mo ago
hi @Devben . did you follow all the debugging steps here? https://docs.convex.dev/auth/debug
Debugging Authentication | Convex Developer Hub
You have followed one of our authentication guides but something is not working.
jamwt
jamwt10mo ago
in our experience it's almost always one of those steps
Devben
DevbenOP10mo ago
Yes you’re right I it’s the first one. I can’t see my log in the log dashboard And my code isn’t throwing any error in the front end browser console neither backend console So am kind of lost
Devben
DevbenOP10mo ago
Thanks man, just check it out, but he doesn’t store the user credentials in convex And connecting convex with clerk isn’t a problem but I can’t see the user credentials @jamwt @erquhart @ian please guys I need help on this, the hackathon will end soon
trace
trace10mo ago
Ohh gotcha
Devben
DevbenOP10mo ago
But I do saw the usestore hook I created in convex function
trace
trace10mo ago
GitHub
convex-nextjs-app-router-demo/convex/schema.ts at main · get-convex...
Demo showing a Next.js App Router app powered by Convex backend - get-convex/convex-nextjs-app-router-demo
trace
trace10mo ago
This one stores it in db
Devben
DevbenOP10mo ago
But can’t see the user credentials that’s the issue and I am not seeing any error in the console Okay thanks man I’ll check 😇😇 @erquhart this is my user.ts in convex folder import { v } from "convex/values"; import { QueryCtx, mutation, query } from "./_generated/server"; export const store = mutation({ args: {}, handler: async (ctx) => { const identity = await ctx.auth.getUserIdentity(); if (!identity) { throw new Error("Called storeUser without authentication present"); } const user = await getUser(ctx, identity.nickname!); if (user !== null) { if ( user.name !== identity.name user.username !== identity.nickname user.pictureUrl !== identity.pictureUrl || user.tokenIdentifier !== identity.tokenIdentifier ) { await ctx.db.patch(user._id, { tokenIdentifier: identity.tokenIdentifier, name: identity.name, username: identity.nickname, pictureUrl: identity.pictureUrl, }); } return user._id; } // If it's a new identity, create a new User. return await ctx.db.insert("users", { tokenIdentifier: identity.tokenIdentifier, name: identity.name!, username: identity.nickname!, pictureUrl: identity.pictureUrl!, numPosts: 0, }); }, }); export const get = query({ args: { username: v.string(), }, handler: async (ctx, args) => { return await getUser(ctx, args.username); }, }); export async function getUser(ctx: QueryCtx, username: string) { return await ctx.db .query("users") .withIndex("username", (q) => q.eq("username", username)) .unique(); } But I can't see any user credential in convex I use github auth in clerk
erquhart
erquhart10mo ago
First thing you want to do is use logging to find where your code is not doing what you expect. Can you confirm that the mutation is running at all?
Devben
DevbenOP10mo ago
No description
Devben
DevbenOP10mo ago
It's definitely running To make it easier to debug
erquhart
erquhart10mo ago
That shows you're running dev successfully, but is the mutation actually running when you call it from your ui
Devben
DevbenOP10mo ago
I saw the function I created in convex function
erquhart
erquhart10mo ago
Your code you originally pasted had a console log with server identity, was that log not printing out at all? Or printing but the value was undefined?
Devben
DevbenOP10mo ago
The issue now is I can't see any user credential in convex dashboard so.... there's no way I can call the user without the usere credential being store in database Yes I followed the convex debug method In convex docs But I can’t seems to see any log in convex dashboard log I followed this steps
Devben
DevbenOP10mo ago
Convex Clerk | Convex Developer Hub
Clerk is an authentication platform providing login via
erquhart
erquhart10mo ago
We need to be clear on what you mean by "can't see any log in convex dashboard" If you put a console log as the first line in the mutation, and then run the mutation from your frontend, does it log? If not that means you're not actually calling the mutation from your frontend
Devben
DevbenOP10mo ago
Still not working Remeber am new lol 😂
erquhart
erquhart10mo ago
No problem lol Can you paste the frontend code that you're using to run the mutation Also, if you paste code, put triple backticks before and after (```), just helps with readability.
Devben
DevbenOP10mo ago
No description
erquhart
erquhart10mo ago
hmm nothing is running at all?
Devben
DevbenOP10mo ago
This is my convex dashboard logs .. after adding the console at the top
erquhart
erquhart10mo ago
Can you paste the react code where you're running the mutation
Devben
DevbenOP10mo ago
import { v } from "convex/values"; import { QueryCtx, mutation, query } from "./_generated/server"; export const store = mutation({
args: {}, handler: async (ctx) => { console.log("server identity", await ctx.auth.getUserIdentity()); const identity = await ctx.auth.getUserIdentity(); if (!identity) { throw new Error("Called storeUser without authentication present"); } const user = await getUser(ctx, identity.nickname!); if (user !== null) { if ( user.name !== identity.name user.username !== identity.nickname user.pictureUrl !== identity.pictureUrl || user.tokenIdentifier !== identity.tokenIdentifier ) { await ctx.db.patch(user._id, { tokenIdentifier: identity.tokenIdentifier, name: identity.name, username: identity.nickname, pictureUrl: identity.pictureUrl, }); } return user._id; } // If it's a new identity, create a new User. return await ctx.db.insert("users", { tokenIdentifier: identity.tokenIdentifier, name: identity.name!, username: identity.nickname!, pictureUrl: identity.pictureUrl!, numPosts: 0, }); }, }); export const get = query({ args: { username: v.string(), }, handler: async (ctx, args) => { return await getUser(ctx, args.username); }, }); export async function getUser(ctx: QueryCtx, username: string) { return await ctx.db .query("users") .withIndex("username", (q) => q.eq("username", username)) .unique(); }
erquhart
erquhart10mo ago
That's your convex code - where in your frontend are you calling the function?
Devben
DevbenOP10mo ago
I haven’t use it yet in my front end I want to make sure it store the user credentials before using it in my front end But with this convex code I should be able to see the user credentials if I login or sign up right ?
erquhart
erquhart10mo ago
Only if you call the mutation, if you're authenticating directly through Clerk nothing will happen in Convex. The above code is just creating functions - the functions have to be executed somewhere
erquhart
erquhart10mo ago
Have you walked through the basic Convex/Clerk auth docs? https://docs.convex.dev/auth/clerk
Convex Clerk | Convex Developer Hub
Clerk is an authentication platform providing login via
Devben
DevbenOP10mo ago
Now am seeing bug Unhandled Runtime Error Error: [CONVEX Q(user:get)] [Request ID: U8BLF4acYTjrzAV8] Server Error ArgumentValidationError: Object is missing the required field username. Consider wrapping the field validator in v.optional(...) if this is expected. Object: {} Validator: v.object({username: v.string()}) Called by client I just use it as an example here 'use client' import { Input } from "@/components/ui/input"; import React from "react"; import { BackgroundBeams } from "@/components/ui/background-beams"; import { Div } from "@/components/ui/moving-borders"; import {UserButton } from "@clerk/nextjs"; import { TextRevealCard } from "@/components/ui/text-reveal"; import { useQuery } from "convex/react"; import { api } from "@/convex/_generated/api"; const Developers = ({ username }: { username: string }) => { const user = useQuery(api.user.get, {username}); return ( <React.Fragment> <main className="h-screen w-full rounded-md bg-neutral-950 relative flex flex-col items-center antialiased"> <div className="h-screen w-full max-w-lg text-white P-4"> <div className="flex justify-between items-center p-4 relative z-10"> <h1 className="text-2xl p-2">LetCollab</h1> <UserButton afterSignOutUrl="/" /> </div> <div className="px-6"> <Input type="text" placeholder="Search" className="rounded-lg p-7 border border-neutral-800 focus:ring-2 focus:ring-teal-500 w-full relative z-10 mt-4 bg-neutral-950 placeholder:text-neutral-700 text-white" /> <section> <h1 className="text-2xl text-white"> This is where the user will be </h1> <h2>@{user?.username}</h2> </section> </div> </div> <BackgroundBeams /> </main> </React.Fragment> ); }; export default Developers;
erquhart
erquhart10mo ago
Ah that's a good sign
Devben
DevbenOP10mo ago
I'm sorry for disturbing
erquhart
erquhart10mo ago
not disturbing at all, this is what support forum is for 👍 So this is progress! It's trying to insert the user, but you're missing the username field and your schema requires it. So you'll either want to make sure you include a username or make the field optional in your schema. If any of that doesn't make sense I can break it down further.
Devben
DevbenOP10mo ago
Yes please do my schema.ts file import { defineSchema, defineTable } from "convex/server"; import { v } from "convex/values"; export default defineSchema({ users: defineTable({ // Unique identifier from the auth provider tokenIdentifier: v.string(), name: v.string(), username: v.string(), pictureUrl: v.string(), numPosts: v.number(), }) .index("tokenIdentifier", ["tokenIdentifier"]) .index("username", ["username"]), posts: defineTable({ authorId: v.id("users"), text: v.string(), }).index("authorId", ["authorId"]), }); Yesssss brother I see some logs lol 😂
erquhart
erquhart10mo ago
hahahaha
Devben
DevbenOP10mo ago
No description
erquhart
erquhart10mo ago
In your convex code, where you're inserting the user, look at the line where you're passing in username - you're using the nickname property of the identity object That property can be undefined, which is why you had to use an exclamation point to make the typescript error go away If you want your users to have unique, required usernames, you'll want to make sure you have usernames enabled in Clerk, and then use that instead of the nickname
Devben
DevbenOP10mo ago
I don't want that I use github auth You mean here right? export const get = query({ args: { username: v.string(), }, handler: async (ctx, args) => { return await getUser(ctx, args.username); }, });
erquhart
erquhart10mo ago
No, in the insert:
// If it's a new identity, create a new User.
return await ctx.db.insert("users", {
tokenIdentifier: identity.tokenIdentifier,
name: identity.name!,
username: identity.nickname!,
pictureUrl: identity.pictureUrl!,
numPosts: 0,
});
// If it's a new identity, create a new User.
return await ctx.db.insert("users", {
tokenIdentifier: identity.tokenIdentifier,
name: identity.name!,
username: identity.nickname!,
pictureUrl: identity.pictureUrl!,
numPosts: 0,
});
That's where you're creating the user If you don't want them to have a username, drop the username line You'll also need to remove the username field from your users table in the schema But if this is all a part of a template, you'll want to search the code and see where the username is being used in the app, as those parts will break once the field is removed
Devben
DevbenOP10mo ago
I'm doing something like this where I can be able to get the user username and name
jamwt
jamwt10mo ago
hi. I'll try to catch up and help in general, make sure you understand your typescript errors (or lints) before you silence them b/c often we'll find we work on an issue with someone and we end up tracing the root cause back to an error or warning that told them what the problem was earlier I strongly recommend you always have your projects be 100% clean of lints warning and errors b/c understanding them and fixing them is usually key to mastering the programming model and libraries you're working with. and warnings/errors will re-emerge as true bugs, that are more mysterious and harder to debug a little further into your project
erquhart
erquhart10mo ago
Part of the confusion is error silencing in the template, so it probably feels like a pattern to follow. I believe OP is using this one: https://github.com/get-convex/convex-demos/blob/d4b6b97ce839ade881109653a6ffe8ea5ff4d082/users-and-clerk/convex/users.ts#L39
jamwt
jamwt10mo ago
fair point!
Devben
DevbenOP10mo ago
Thank you so much Jamie, I’ll try to always avoid the errors am a baby developer lol 😂 @erquhart Thank you so much for yesterday, so.... the demo you sent show the name of the person that login but I can't seems to find it in the database This is how I use this in my frontend for example <span className="text-white text-4xl">Logged in{user!.username ? as ${user!.fullName} : ""}</span>

Did you find this page helpful?