Convex
Learn how to integrate Clerk into your Convex application
Getting started
Navigate to the JWT Templates screen from the Clerk Dashboard and click on the button to create a New Template based on Convex.
This will pre-populate the default audience (aud
) claim required by Convex. You can include additional claims as necessary. Shortcodes are available to make adding dynamic user values easy.
By default, Clerk will sign the JWT with a private key automatically generated for your application, which is what most developers use for Convex. If you so choose, you can customize this key.
Don't forget to click Apply Changes to save your JWT template.
Configure Convex
The next step is to configure Convex with the issuer domain provided by Clerk. From your Clerk JWT template screen, find the Issuer input and click to Copy the URL.
In your terminal, run the following command from your Convex app directory:
npx convex auth add
Paste the Issuer URL you copied when it prompts you for the identity provider's URL.
The application/client ID will need to match the aud
claim (default is convex
).
? Enter the identity provider's URL: https://frontend_api_url? Enter your application/client ID with this identity provider: convex? Would you like to add another provider? NoConfiguration updated. Run `npx convex push` to sync these changes with your backend.
Configure the providers
Both Clerk and Convex have Provider components that are required to wrap your React application to provide the authentication and client context.
1import '../styles/globals.css'2import type { AppProps } from 'next/app'3import { ClerkProvider, SignIn, useAuth } from '@clerk/nextjs'4import { ConvexProvider, ConvexReactClient } from 'convex/react'5import clientConfig from '../convex/_generated/clientConfig'6import { ReactElement, ReactNode, useEffect, useState } from 'react'78const convex = new ConvexReactClient(clientConfig)910const ConvexProviderWithClerk = ({11children,12client,13loading,14loggedOut,15}: {16children?: ReactNode17client: any18loading?: ReactElement19loggedOut?: ReactElement20}) => {21const { getToken, isSignedIn, isLoaded } = useAuth()22const [clientAuthed, setClientAuthed] = useState(false)2324useEffect(() => {25async function setAuth() {26const token = await getToken({ template: 'convex', skipCache: true })27if (token) {28client.setAuth(token)29setClientAuthed(true)30}31}32if (isSignedIn) {33const intervalId = setInterval(() => setAuth(), 50000)34setAuth()35return () => {36clearInterval(intervalId)37}38}39}, [client, getToken, isSignedIn])4041if (!isLoaded || (isSignedIn && !clientAuthed)) {42return loading || null43} else if (!isSignedIn) {44return loggedOut || <SignIn />45}4647return <ConvexProvider client={client}>{children}</ConvexProvider>48}4950function MyApp({ Component, pageProps }: AppProps) {51return (52<ClerkProvider>53<ConvexProviderWithClerk client={convex} loading={<div>loading...</div>}>54<Component {...pageProps} />55</ConvexProviderWithClerk>56</ClerkProvider>57)58}5960export default MyApp
Access user identity
In some cases you may need to access the user when using Convex queries and mutations, you can use the getUserIdentity()
method provided on the auth
property, which is passed to the context argument of every Convex function invocation.
convex/getUser.ts1import type { UserIdentity } from 'convex/server';2import { query } from './_generated/server';34export default query(async ({ auth }): Promise<UserIdentity | null> => {5const identity = await auth.getUserIdentity();67return identity;8});
convex/getUser.ts1import type { UserIdentity } from 'convex/server';2import { query } from './_generated/server';3456export default query(async ({ auth }): Promise<UserIdentity | null> => {7const identity = await auth.getUserIdentity();89return identity;10});
property, which is passed to the context argument of every Convex function invocation.
convex/getUser.tsimport type { UserIdentity } from 'convex/server';import { query } from './_generated/server';export default query(async ({ auth }): Promise<UserIdentity | null> => {const identity = await auth.getUserIdentity();return identity;});