Docs

Auth and Clerk

Configure Clerk as the authentication layer for Convoy deployments, including the JWT template and user sync flow.

Convoy uses Clerk for user authentication. The web app signs users in through Clerk; Convex validates those sessions through a JWT issuer configured to match the same Clerk instance. Authorization (who can do what inside Convoy) is separate from this and lives in the project's organization/project permission model.

Required env vars

Set these Clerk-related env vars in the places listed.

VariableWherePurpose
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEYWeb hostBrowser-side Clerk client
CLERK_SECRET_KEYWeb hostServer-side Clerk client
NEXT_PUBLIC_CLERK_SIGN_IN_URLWeb hostTypically /auth/sign-in
NEXT_PUBLIC_CLERK_SIGN_UP_URLWeb hostTypically /auth/sign-up
NEXT_PUBLIC_CLERK_SIGN_IN_FALLBACK_REDIRECT_URLWeb hostPost-sign-in, typically /auth/callback
NEXT_PUBLIC_CLERK_SIGN_UP_FALLBACK_REDIRECT_URLWeb hostPost-sign-up, typically /auth/callback
CLERK_JWT_ISSUER_DOMAINConvex dashboardIssuer domain Convex validates JWTs against

See Environment Variables for the full matrix.

How Clerk and Convex are wired

Convoy's apps/web/convex/auth.config.ts registers a single JWT provider, keyed on the Clerk issuer domain you configure in the Convex dashboard:

export default {
  providers: [
    {
      domain: process.env.CLERK_JWT_ISSUER_DOMAIN!,
      applicationID: "convex",
    },
  ],
} satisfies AuthConfig;

That applicationID: "convex" value is what the Clerk JWT template's audience (aud) must be set to for Convex to accept the token.

Configure the JWT template in Clerk

  1. Open the Clerk dashboard for the app you want Convex to trust.
  2. Go to JWT TemplatesNew template.
  3. Use the built-in Convex preset if Clerk offers it. If creating manually, set:
    • Name: convex
    • Signing algorithm: RS256 (default)
    • Lifetime / Allowed clock skew: defaults are fine
    • Claims: at minimum, "aud": "convex". Clerk's preset also populates the Clerk standard claims Convoy expects (sub, email, name, picture_url).
  4. Save.
  5. Copy the Issuer field from Clerk (looks like https://your-app.clerk.accounts.dev in dev, or your configured custom domain in prod). That is the value CLERK_JWT_ISSUER_DOMAIN must match in your Convex dashboard environment variables.

Allowed origins and redirect URLs

In the Clerk dashboard, under Paths / Domains and Frontend API, make sure:

  • the deployed web app origin is listed as an allowed origin
  • the sign-in, sign-up, and callback paths match the NEXT_PUBLIC_*_URL values you set on the web host
  • OAuth/social provider redirect URIs on the Clerk side match the deployed host

Mismatches usually surface as "invalid session" errors immediately after a user signs in.

User sync flow (how a Clerk user becomes a Convoy user)

On sign-in, the web app calls the Convex users.store mutation. That mutation reads ctx.auth.getUserIdentity() (which Convex populates from the validated Clerk JWT) and upserts a row in users keyed on tokenIdentifier:

  • First call: creates a users row with email, name, and avatarUrl from the Clerk identity.
  • Subsequent calls: updates email / name / avatarUrl if they have changed since the last sign-in.

On first onboarding, users.onboard additionally bootstraps the user's first organization membership. A tokenIdentifier that doesn't match any existing users row is an implicit "new user" signal — the onboarding path handles it.

If sign-in succeeds in Clerk but Convoy never sees the user, the Clerk JWT template or the Convex CLERK_JWT_ISSUER_DOMAIN is usually the problem. Convex's Functions → Logs tab will show failed users.store calls when the identity is missing.

Environment separation

Keep production and non-production Clerk instances separate. A non-production deployment that points at a production Clerk app will happily sync production users into its own Convex, which is almost never what you want.

EnvironmentClerk appConvex deploymentCLERK_JWT_ISSUER_DOMAIN
Devdev Clerk appdev:... Convexissuer of the dev Clerk app
Stagingstaging Clerk appstaging Convexissuer of the staging Clerk app
Prodprod Clerk appprod:... Convexissuer of the prod Clerk app

Enterprise / SSO

Clerk supports SSO (SAML, OIDC), domain restriction, machine users, and allowlists — Convoy inherits whatever Clerk exposes. The setup lives in the Clerk dashboard, not in Convoy. See Clerk's own docs for the authoritative list; once configured, nothing in Convoy needs to change.

What this does not replace

Clerk answers "is this request authenticated and who is it?". It does not answer "can this user do this?". Authorization decisions happen inside Convex functions via Convoy's organization and project permission helpers (convex/lib/access/permissions.ts).

On this page