- Clerk account with an application created
- Node.js/Bun installed
npx convex initThis will:
- Create a new Convex project
- Generate the
convex/_generateddirectory - Provide your
VITE_CONVEX_URL
Add to .env.local:
# From Convex dashboard after running convex init
VITE_CONVEX_URL=https://your-app.convex.cloud
# From Clerk Dashboard -> API Keys
VITE_CLERK_PUBLISHABLE_KEY=pk_test_...
CLERK_SECRET_KEY=sk_test_...
# From Clerk Dashboard -> API Keys -> JWT Templates
# Create a "Convex" template with the issuer URL
CLERK_JWT_ISSUER_DOMAIN=https://your-app.clerk.accounts.devIn Clerk Dashboard:
- Go to API Keys -> JWT Templates
- Create a new template called "Convex"
- Set the following claims:
{ "sub": "{{user.id}}", "email": "{{user.email_addresses[0].email_address}}", "name": "{{user.full_name}}", "given_name": "{{user.first_name}}", "family_name": "{{user.last_name}}", "nickname": "{{user.username}}", "picture": "{{user.image_url}}" } - Copy the Issuer URL to
CLERK_JWT_ISSUER_DOMAIN
npx convex env set CLERK_JWT_ISSUER_DOMAIN "https://your-app.clerk.accounts.dev"npx convex dev
# or for production
npx convex deployFor better user sync, set up a webhook in Clerk:
- Go to Webhooks in Clerk Dashboard
- Add endpoint:
https://your-app.convex.site/clerk-webhook - Select events:
user.createduser.updateduser.deleted
-
Authentication Flow:
- User signs in via Clerk
- Clerk issues a JWT token
- ConvexProviderWithAuth passes the token to Convex
- Convex verifies the JWT using Clerk's public key
-
User Sync:
- On first login, the user is automatically created in Convex
- User data is synced from Clerk JWT claims
- Optional webhook keeps user data in sync
-
Authorization:
- Each Convex function uses
requireAuth()to verify authentication - User data is fetched from Convex database using Clerk ID
- Functions have access to full user object
- Each Convex function uses
- Ensure the user is synced to Convex (check
useClerkConvexSynchook) - Verify JWT claims are configured correctly in Clerk
- Check
CLERK_JWT_ISSUER_DOMAINmatches Clerk's issuer URL - Ensure environment variables are set in both
.env.localand Convex - Verify JWT template is active in Clerk
- Convex handles CORS automatically
- Ensure you're using the correct Convex URL