React (Vite SPA)
Install and configure Convex + Better Auth for React.
Check out a complete Convex + Better Auth example with React in the GitHub repo.
Installation
Install packages
Install the component, a pinned version of Better Auth, and ensure the latest version of Convex.
1.25.0
or later.npm install better-auth@1.3.8 --save-exact
npm install convex@latest @convex-dev/better-auth
Register the component
Register the Better Auth component in your Convex project.
import { defineApp } from "convex/server";
import betterAuth from "@convex-dev/better-auth/convex.config";
const app = defineApp();
app.use(betterAuth);
export default app;
Add Convex auth config
Add a convex/auth.config.ts
file to configure Better Auth as an authentication provider.
export default {
providers: [
{
domain: process.env.CONVEX_SITE_URL,
applicationID: "convex",
},
],
};
Set environment variables
Generate a secret for encryption and generating hashes. Use the command below if you have openssl installed, or use the button to generate a random value instead. Or generate your own however you like.
npx convex env set BETTER_AUTH_SECRET=$(openssl rand -base64 32)
Add your site URL to your Convex deployment.
npx convex env set SITE_URL http://localhost:5173
Add environment variables to the .env.local
file created by npx convex dev
. It will be picked up by your framework dev server.
# Deployment used by \`npx convex dev\`
CONVEX_DEPLOYMENT=dev:adjective-animal-123 # team: team-name, project: project-name
VITE_CONVEX_URL=https://adjective-animal-123.convex.cloud
# Same as VITE_CONVEX_URL but ends in .site
VITE_CONVEX_SITE_URL=https://adjective-animal-123.convex.site
# Your local site URL
SITE_URL=http://localhost:5173
Create a Better Auth instance
Create a Better Auth instance and initialize the component.
import { createClient, type GenericCtx } from "@convex-dev/better-auth";
import { convex, crossDomain } from "@convex-dev/better-auth/plugins";
import { components } from "./_generated/api";
import { DataModel } from "./_generated/dataModel";
import { query } from "./_generated/server";
import { betterAuth } from "better-auth";
const siteUrl = process.env.SITE_URL!;
// The component client has methods needed for integrating Convex with Better Auth,
// as well as helper methods for general use.
export const authComponent = createClient<DataModel>(components.betterAuth);
export const createAuth = (
ctx: GenericCtx<DataModel>,
{ optionsOnly } = { optionsOnly: false },
) => {
return betterAuth({
// disable logging when createAuth is called just to generate options.
// this is not required, but there's a lot of noise in logs without it.
logger: {
disabled: optionsOnly,
},
trustedOrigins: [siteUrl],
database: authComponent.adapter(ctx),
// Configure simple, non-verified email/password to get started
emailAndPassword: {
enabled: true,
requireEmailVerification: false,
},
plugins: [
// The cross domain plugin is required for client side frameworks
crossDomain({ siteUrl }),
// The Convex plugin is required for Convex compatibility
convex(),
],
});
};
// Example function for getting the current user
// Feel free to edit, omit, etc.
export const getCurrentUser = query({
args: {},
handler: async (ctx) => {
return authComponent.getAuthUser(ctx);
},
});
Create a Better Auth client instance
Create a Better Auth client instance for interacting with the Better Auth server from your client.
import { createAuthClient } from "better-auth/react";
import {
convexClient,
crossDomainClient,
} from "@convex-dev/better-auth/client/plugins";
export const authClient = createAuthClient({
baseURL: import.meta.env.VITE_CONVEX_SITE_URL,
plugins: [convexClient(), crossDomainClient()],
});
Mount handlers
Register Better Auth route handlers on your Convex deployment.
import { httpRouter } from "convex/server";
import { authComponent, createAuth } from "./auth";
const http = httpRouter();
// CORS handling is required for client side frameworks
authComponent.registerRoutes(http, createAuth, { cors: true });
export default http;
Set up Convex client provider
Wrap your app with the ConvexBetterAuthProvider
component.
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import "./index.css";
import { ConvexReactClient } from "convex/react";
import { ConvexBetterAuthProvider } from "@convex-dev/better-auth/react";
import { authClient } from "@/lib/auth-client";
const convex = new ConvexReactClient(import.meta.env.VITE_CONVEX_URL as string, {
// Optionally pause queries until the user is authenticated
expectAuth: true,
});
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<ConvexBetterAuthProvider client={convex} authClient={authClient}>
<App />
</ConvexBetterAuthProvider>
</React.StrictMode>
);
You're done!
You're now ready to start using Better Auth with Convex.