Authenticate users
Wire an identity provider into Nimbus so functions can verify who is calling them.
Nimbus verifies JWTs from Auth0, Clerk, Firebase Auth, Keycloak, and other
identity providers. The provider must support OIDC or publish a JSON Web Key
Set (JWKS). Nimbus exposes the verified identity through ctx.auth. This guide
wires a provider into a Convex-style project.
1. Declare the provider
Create exactly one config file: convex/auth.config.ts or
convex/auth.config.js. Add a default export that lists your providers.
For an OIDC provider:
// convex/auth.config.ts
export default {
providers: [
{
domain: "https://your-tenant.us.auth0.com",
applicationID: "your-client-id",
},
],
};domainis the token issuer. Nimbus discovers the signing keys from{domain}/.well-known/openid-configuration.applicationIDmust equal theaudclaim of the tokens your provider issues. Nimbus rejects tokens with multiple audiences.
For a provider that is not a full OIDC issuer but publishes a JWKS:
// convex/auth.config.ts
export default {
providers: [
{
type: "customJwt",
issuer: "https://auth.example.com",
jwks: "https://auth.example.com/.well-known/jwks.json",
algorithm: "RS256", // or "ES256"
applicationID: "your-client-id", // optional
},
],
};Codegen evaluates the config statically. It resolves process.env.* reads
against the codegen environment. You can therefore keep issuer URLs out of
source:
export default {
providers: [
{
domain: process.env.AUTH_ISSUER!,
applicationID: process.env.AUTH_CLIENT_ID!,
},
],
};nimbus dev loads the config on the next codegen pass. A running dev loop
starts that pass when you save the file.
2. Send tokens from the client
In React, wrap your app in ConvexProviderWithAuth and supply a useAuth
hook that bridges your auth library:
import { ConvexProviderWithAuth, ConvexReactClient } from "convex/react";
const client = new ConvexReactClient("http://localhost:3210/convex/demo");
function useAuthFromMyProvider() {
// Adapt your auth library to this shape.
return {
isLoading: false,
isAuthenticated: true,
fetchAccessToken: async ({ forceRefreshToken }) =>
await myAuthLibrary.getToken({ ignoreCache: forceRefreshToken }),
};
}
export function App({ children }) {
return (
<ConvexProviderWithAuth client={client} useAuth={useAuthFromMyProvider}>
{children}
</ConvexProviderWithAuth>
);
}useConvexAuth() reports { isLoading, isAuthenticated } from anywhere
under the provider. Outside React, set the token directly on the client. Use
either a string or an async fetcher that runs again when the token needs a
refresh. Clear the token on sign-out:
client.setAuth(async () => await getFreshToken());
// ...later
client.clearAuth();3. Read the identity in functions
Inside any query, mutation, or action, ctx.auth.getUserIdentity() returns
the verified identity, or null when the request carries no valid token:
import { mutation } from "./_generated/server";
import { v } from "convex/values";
export const send = mutation({
args: { body: v.string() },
handler: async (ctx, { body }) => {
const identity = await ctx.auth.getUserIdentity();
if (identity === null) {
throw new Error("Not signed in");
}
await ctx.db.insert("messages", {
author: identity.tokenIdentifier,
body,
});
},
});tokenIdentifier has the form issuer|subject and is stable for each user
and provider. Use it as the foreign key for user records. Your code owns
authorization. Check the identity and decide what the caller may do. Nimbus
has no separate rules language.
What Nimbus verifies
For each request token, Nimbus checks the signature against the provider's
published keys and the issuer against your config. When you set
applicationID, Nimbus also checks the audience. A request without a token
runs your function, and getUserIdentity() returns null. Nimbus rejects an
invalid or expired token before your function runs.
Next steps
- Compatibility reference: the full authentication surface.
- Build with the Convex API: functions, schema, and the dev loop.
Build your first app
A complete tutorial — scaffold a Nimbus project, define a schema, write functions, and watch live queries update in real time.
Adapters
Nimbus speaks the protocols your clients already use — one engine behind several front doors. What an adapter is, how each surface is served, and which one to reach for.