Clerk logo

Clerk Docs

Ctrl + K
Go to clerk.devGet API keys

Convex

Learn how to integrate Clerk into your Convex application

Overview

Convex is a serverless state management platform that makes it easy to store your app's shared state and keep it in sync with automatic subscriptions.

Although Convex does not handle user authentication, you can connect your Convex app with identity providers like Clerk to handle all your authentication and user management needs.

The Clerk integration with Convex works using a JSON Web Token (JWT) created with our JWT Templates feature.

Getting started

Add Convex JWT template

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.

Convex JWT claims

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://<YOUR_CLERK_FRONTEND_API>
? Enter your application/client ID with this identity provider: convex
? Would you like to add another provider? No
Configuration 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.

1
import '../styles/globals.css'
2
import type { AppProps } from 'next/app'
3
import { ClerkProvider, SignIn, useAuth } from '@clerk/nextjs'
4
import { ConvexProvider, ConvexReactClient } from 'convex/react'
5
import clientConfig from '../convex/_generated/clientConfig'
6
import { ReactElement, ReactNode, useEffect, useState } from 'react'
7
8
const convex = new ConvexReactClient(clientConfig)
9
10
const ConvexProviderWithClerk = ({
11
children,
12
client,
13
loading,
14
loggedOut,
15
}: {
16
children?: ReactNode
17
client: any
18
loading?: ReactElement
19
loggedOut?: ReactElement
20
}) => {
21
const { getToken, isSignedIn, isLoaded } = useAuth()
22
const [clientAuthed, setClientAuthed] = useState(false)
23
24
useEffect(() => {
25
async function setAuth() {
26
const token = await getToken({ template: 'convex', skipCache: true })
27
if (token) {
28
client.setAuth(token)
29
setClientAuthed(true)
30
}
31
}
32
if (isSignedIn) {
33
const intervalId = setInterval(() => setAuth(), 50000)
34
setAuth()
35
return () => {
36
clearInterval(intervalId)
37
}
38
}
39
}, [client, getToken, isSignedIn])
40
41
if (!isLoaded || (isSignedIn && !clientAuthed)) {
42
return loading || null
43
} else if (!isSignedIn) {
44
return loggedOut || <SignIn />
45
}
46
47
return <ConvexProvider client={client}>{children}</ConvexProvider>
48
}
49
50
function MyApp({ Component, pageProps }: AppProps) {
51
return (
52
<ClerkProvider>
53
<ConvexProviderWithClerk client={convex} loading={<div>loading...</div>}>
54
<Component {...pageProps} />
55
</ConvexProviderWithClerk>
56
</ClerkProvider>
57
)
58
}
59
60
export default MyApp
61
1
import type { ReactElement, ReactNode } from 'react';
2
import { StrictMode, useState, useEffect } from 'react';
3
import ReactDOM from 'react-dom';
4
import { ClerkProvider, SignIn, UserButton, useAuth } from '@clerk/clerk-react';
5
import { ConvexProvider, ConvexReactClient } from 'convex/react';
6
import clientConfig from '../convex/_generated/clientConfig'
7
import { ReactElement, ReactNode, useEffect, useState } from 'react'
8
import App from './App';
9
10
const convex = new ConvexReactClient(clientConfig)
11
12
const ConvexProviderWithClerk = ({
13
children,
14
client,
15
loading,
16
loggedOut
17
}: {
18
children?: ReactNode;
19
client: any;
20
loading?: ReactElement;
21
loggedOut?: ReactElement;
22
}) => {
23
const { getToken, isSignedIn, isLoaded } = useAuth();
24
const [clientAuthed, setClientAuthed] = useState(false);
25
26
useEffect(() => {
27
async function setAuth() {
28
// Use the name of the JWT template. Default is 'convex'
29
const token = await getToken({ template: 'convex', skipCache: true });
30
if(token){
31
await client.setAuth(token);
32
setClientAuthed(true);
33
}
34
}
35
36
if (isSignedIn) {
37
const intervalId = setInterval(() => setAuth(), 50000);
38
setAuth();
39
return () => {
40
clearInterval(intervalId);
41
};
42
}
43
}, [client, getToken, isSignedIn]);
44
45
if (!isLoaded || (isSignedIn && !clientAuthed)) {
46
return loading || null;
47
} else if (!isSignedIn) {
48
return loggedOut || <SignIn />;
49
}
50
51
return <ConvexProvider client={client}>{children}</ConvexProvider>;
52
};
53
54
ReactDOM.render(
55
<StrictMode>
56
<ClerkProvider frontendApi={<REPLACE_WITH_CLERK_FRONTEND_API>}>
57
<ConvexProviderWithClerk client={convex} loading={<div>Loading...</div>}>
58
<UserButton />
59
<App />
60
</ConvexProviderWithClerk>
61
</ClerkProvider>
62
</StrictMode>,
63
document.getElementById('root')
64
);
65

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.ts
import 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;
});

Was this helpful?

Clerk © 2022