mirror of
https://github.com/LukeHagar/better-auth.git
synced 2025-12-09 20:27:44 +00:00
docs: add Convex integration (#4785)
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> Co-authored-by: Bereket Engida <86073083+Bekacru@users.noreply.github.com> Co-authored-by: TheUntraceable <73362400+TheUntraceable@users.noreply.github.com>
This commit is contained in:
@@ -561,4 +561,27 @@ export const Icons = {
|
||||
/>
|
||||
</svg>
|
||||
),
|
||||
convex: (props?: SVGProps<any>) => (
|
||||
<svg
|
||||
width="1.2em"
|
||||
height="1.2em"
|
||||
viewBox="15 15 160 160"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M108.092 130.021C126.258 128.003 143.385 118.323 152.815 102.167C148.349 142.128 104.653 167.385 68.9858 151.878C65.6992 150.453 62.8702 148.082 60.9288 145.034C52.9134 132.448 50.2786 116.433 54.0644 101.899C64.881 120.567 86.8748 132.01 108.092 130.021Z"
|
||||
fill="currentColor"
|
||||
></path>
|
||||
<path
|
||||
d="M53.4012 90.1735C46.0375 107.19 45.7186 127.114 54.7463 143.51C22.9759 119.608 23.3226 68.4578 54.358 44.7949C57.2286 42.6078 60.64 41.3096 64.2178 41.1121C78.9312 40.336 93.8804 46.0225 104.364 56.6193C83.0637 56.8309 62.318 70.4756 53.4012 90.1735Z"
|
||||
fill="currentColor"
|
||||
></path>
|
||||
<path
|
||||
d="M114.637 61.8552C103.89 46.8701 87.0686 36.6684 68.6387 36.358C104.264 20.1876 148.085 46.4045 152.856 85.1654C153.3 88.7635 152.717 92.4322 151.122 95.6775C144.466 109.195 132.124 119.679 117.702 123.559C128.269 103.96 126.965 80.0151 114.637 61.8552Z"
|
||||
fill="currentColor"
|
||||
></path>
|
||||
</svg>
|
||||
),
|
||||
};
|
||||
|
||||
@@ -1391,6 +1391,11 @@ C0.7,239.6,62.1,0.5,62.2,0.4c0,0,54,13.8,119.9,30.8S302.1,62,302.2,62c0.2,0,0.2,
|
||||
icon: Icons.nestJS,
|
||||
href: "/docs/integrations/nestjs",
|
||||
},
|
||||
{
|
||||
title: "Convex",
|
||||
icon: Icons.convex,
|
||||
href: "/docs/integrations/convex",
|
||||
},
|
||||
{
|
||||
group: true,
|
||||
title: "Mobile & Desktop",
|
||||
|
||||
347
docs/content/docs/integrations/convex.mdx
Normal file
347
docs/content/docs/integrations/convex.mdx
Normal file
@@ -0,0 +1,347 @@
|
||||
---
|
||||
title: Convex Integration
|
||||
description: Integrate Better Auth with Convex.
|
||||
---
|
||||
|
||||
<Callout>
|
||||
This documentation comes from the [Convex documentation](https://convex-better-auth.netlify.app/),
|
||||
for more information, please refer to their documentation.
|
||||
</Callout>
|
||||
|
||||
## Prerequisites
|
||||
|
||||
<Steps>
|
||||
<Step>
|
||||
### Create a Convex project
|
||||
|
||||
To use Convex + Better Auth, you'll first need a [Convex](https://www.convex.dev/) project.
|
||||
If you don't have one, run the following command to get started.
|
||||
```package-install
|
||||
npm create convex@latest
|
||||
```
|
||||
|
||||
Check out the [Convex docs](https://docs.convex.dev/home) to learn more about Convex.
|
||||
|
||||
</Step>
|
||||
|
||||
<Step>
|
||||
|
||||
### Run `convex dev`
|
||||
|
||||
Running the CLI during setup will initialize your Convex deployment
|
||||
if it doesn't already exist, and keeps generated types current through the process. Keep it running.
|
||||
|
||||
```package-install
|
||||
npx convex dev
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
|
||||
|
||||
## Installation of Convex + Better Auth
|
||||
|
||||
The following documentation assumes you're using Next.js.
|
||||
|
||||
If you're not using Next.js, please refer to the [installation guide by Convex](https://convex-better-auth.netlify.app/#select-your-framework).
|
||||
|
||||
<Callout>
|
||||
For a complete example, check out Convex + Better Auth example with Next.js in this [Github repository](https://github.com/get-convex/better-auth/tree/main/examples/next).
|
||||
</Callout>
|
||||
|
||||
### Installation
|
||||
|
||||
<Steps>
|
||||
<Step>
|
||||
#### Install packages
|
||||
|
||||
Install the component, a pinned version of Better Auth, and ensure the latest version of Convex.
|
||||
|
||||
|
||||
<Callout>
|
||||
This component requires Convex `1.25.0` or later.
|
||||
</Callout>
|
||||
|
||||
```package-install
|
||||
npm install better-auth@1.3.8 --save-exact
|
||||
npm install convex@latest @convex-dev/better-auth
|
||||
```
|
||||
</Step>
|
||||
<Step>
|
||||
#### Register the component
|
||||
|
||||
Register the Better Auth component in your Convex project.
|
||||
|
||||
```ts title="convex/convex.config.ts"
|
||||
import { defineApp } from "convex/server";
|
||||
import betterAuth from "@convex-dev/better-auth/convex.config";
|
||||
|
||||
const app = defineApp();
|
||||
app.use(betterAuth);
|
||||
|
||||
export default app;
|
||||
```
|
||||
</Step>
|
||||
<Step>
|
||||
#### Add Convex auth config
|
||||
|
||||
Add a `convex/auth.config.ts` file to configure Better Auth as an authentication provider.
|
||||
|
||||
|
||||
|
||||
```ts title="convex/auth.config.ts"
|
||||
export default {
|
||||
providers: [
|
||||
{
|
||||
domain: process.env.CONVEX_SITE_URL,
|
||||
applicationID: "convex",
|
||||
},
|
||||
],
|
||||
};
|
||||
```
|
||||
</Step>
|
||||
<Step>
|
||||
#### 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.
|
||||
|
||||
```package-install
|
||||
npx convex env set BETTER_AUTH_SECRET=$(openssl rand -base64 32)
|
||||
```
|
||||
|
||||
Add your site URL to your Convex deployment.
|
||||
|
||||
```package-install
|
||||
npx convex env set SITE_URL http://localhost:3000
|
||||
```
|
||||
|
||||
Add environment variables to the `.env.local` file created by `npx convex dev`.
|
||||
It will be picked up by your framework dev server.
|
||||
|
||||
```shell title=".env.local" tab="Cloud"
|
||||
# Deployment used by \`npx convex dev\`
|
||||
CONVEX_DEPLOYMENT=dev:adjective-animal-123 # team: team-name, project: project-name
|
||||
|
||||
NEXT_PUBLIC_CONVEX_URL=https://adjective-animal-123.convex.cloud
|
||||
|
||||
# Same as NEXT_PUBLIC_CONVEX_URL but ends in .site // [!code ++]
|
||||
NEXT_PUBLIC_CONVEX_SITE_URL=https://adjective-animal-123.convex.site # [!code ++]
|
||||
|
||||
# Your local site URL // [!code ++]
|
||||
SITE_URL=http://localhost:3000 # [!code ++]
|
||||
```
|
||||
|
||||
```shell title=".env.local" tab="Self hosted"
|
||||
# Deployment used by \`npx convex dev\`
|
||||
CONVEX_DEPLOYMENT=dev:adjective-animal-123 # team: team-name, project: project-name
|
||||
|
||||
NEXT_PUBLIC_CONVEX_URL=http://127.0.0.1:3210
|
||||
|
||||
# Will generally be one number higher than NEXT_PUBLIC_CONVEX_URL,
|
||||
# so if your convex url is :3212, your site url will be :3213
|
||||
NEXT_PUBLIC_CONVEX_SITE_URL=http://127.0.0.1:3211 # [!code ++]
|
||||
|
||||
# Your local site URL // [!code ++]
|
||||
SITE_URL=http://localhost:3000 # [!code ++]
|
||||
```
|
||||
</Step>
|
||||
<Step>
|
||||
### Create a Better Auth instance
|
||||
Create a Better Auth instance and initialize the component.
|
||||
|
||||
<Callout>Some TypeScript errors will show until you save the file.</Callout>
|
||||
|
||||
```ts title="convex/auth.ts"
|
||||
import { createClient, type GenericCtx } from "@convex-dev/better-auth";
|
||||
import { convex } 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,
|
||||
},
|
||||
baseURL: siteUrl,
|
||||
database: authComponent.adapter(ctx),
|
||||
// Configure simple, non-verified email/password to get started
|
||||
emailAndPassword: {
|
||||
enabled: true,
|
||||
requireEmailVerification: false,
|
||||
},
|
||||
plugins: [
|
||||
// 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);
|
||||
},
|
||||
});
|
||||
```
|
||||
</Step>
|
||||
<Step>
|
||||
### Create a Better Auth client instance
|
||||
|
||||
Create a Better Auth client instance for interacting with the Better Auth server from your client.
|
||||
|
||||
```ts title="src/lib/auth-client.ts"
|
||||
import { createAuthClient } from "better-auth/react";
|
||||
import { convexClient } from "@convex-dev/better-auth/client/plugins";
|
||||
|
||||
export const authClient = createAuthClient({
|
||||
plugins: [convexClient()],
|
||||
});
|
||||
```
|
||||
</Step>
|
||||
<Step>
|
||||
### Mount handlers
|
||||
|
||||
Register Better Auth route handlers on your Convex deployment.
|
||||
|
||||
```ts title="convex/http.ts"
|
||||
import { httpRouter } from "convex/server";
|
||||
import { authComponent, createAuth } from "./auth";
|
||||
|
||||
const http = httpRouter();
|
||||
|
||||
authComponent.registerRoutes(http, createAuth);
|
||||
|
||||
export default http;
|
||||
```
|
||||
|
||||
Set up route handlers to proxy auth requests from your framework server to your Convex deployment.
|
||||
|
||||
```ts title="app/api/auth/[...all]/route.ts"
|
||||
import { nextJsHandler } from "@convex-dev/better-auth/nextjs";
|
||||
|
||||
export const { GET, POST } = nextJsHandler();
|
||||
```
|
||||
</Step>
|
||||
<Step>
|
||||
### Set up Convex client provider
|
||||
|
||||
Wrap your app with the `ConvexBetterAuthProvider` component.
|
||||
|
||||
```ts title="app/ConvexClientProvider.tsx"
|
||||
"use client";
|
||||
|
||||
import { ReactNode } from "react";
|
||||
import { ConvexReactClient } from "convex/react";
|
||||
import { authClient } from "@/lib/auth-client"; // [!code ++]
|
||||
import { ConvexBetterAuthProvider } from "@convex-dev/better-auth/react"; // [!code ++]
|
||||
|
||||
const convex = new ConvexReactClient(process.env.NEXT_PUBLIC_CONVEX_URL!, {
|
||||
// Optionally pause queries until the user is authenticated // [!code ++]
|
||||
expectAuth: true, // [!code ++]
|
||||
});
|
||||
|
||||
export function ConvexClientProvider({ children }: { children: ReactNode }) {
|
||||
return (
|
||||
<ConvexBetterAuthProvider client={convex} authClient={authClient}> // [!code ++]
|
||||
{children}
|
||||
</ConvexBetterAuthProvider> // [!code ++]
|
||||
);
|
||||
}
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
|
||||
### You're done!
|
||||
|
||||
You're now ready to start using Better Auth with Convex.
|
||||
|
||||
## Usage
|
||||
|
||||
### Using Better Auth from the server
|
||||
|
||||
To use Better Auth's [server
|
||||
methods](https://www.better-auth.com/docs/concepts/api) in server rendering,
|
||||
server functions, or any other Next.js server code, use Convex functions
|
||||
and call the function from your server code.
|
||||
|
||||
First, a token helper for calling Convex functions from your server code.
|
||||
|
||||
```ts title="src/lib/auth-server.ts"
|
||||
import { createAuth } from "convex/auth";
|
||||
import { getToken as getTokenNextjs } from "@convex-dev/better-auth/nextjs";
|
||||
|
||||
export const getToken = () => {
|
||||
return getTokenNextjs(createAuth);
|
||||
};
|
||||
```
|
||||
|
||||
Here's an example Convex function that uses Better Auth's server methods, and
|
||||
a server action that calls the Convex function.
|
||||
|
||||
```ts title="convex/users.ts"
|
||||
import { mutation } from "./_generated/server";
|
||||
import { v } from "convex/values";
|
||||
import { createAuth, authComponent } from "./auth";
|
||||
|
||||
export const updateUserPassword = mutation({
|
||||
args: {
|
||||
currentPassword: v.string(),
|
||||
newPassword: v.string(),
|
||||
},
|
||||
handler: async (ctx, args) => {
|
||||
await createAuth(ctx).api.changePassword({
|
||||
body: {
|
||||
currentPassword: args.currentPassword,
|
||||
newPassword: args.newPassword,
|
||||
},
|
||||
headers: await authComponent.getHeaders(ctx),
|
||||
});
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
```ts title="app/actions.ts"
|
||||
"use server";
|
||||
|
||||
import { fetchMutation } from "convex/nextjs";
|
||||
import { api } from "../convex/_generated/api";
|
||||
import { getToken } from "../lib/auth-server";
|
||||
|
||||
// Authenticated mutation via server function
|
||||
export async function updatePassword({
|
||||
currentPassword,
|
||||
newPassword,
|
||||
}: {
|
||||
currentPassword: string;
|
||||
newPassword: string;
|
||||
}) {
|
||||
const token = await getToken();
|
||||
await fetchMutation(
|
||||
api.users.updatePassword,
|
||||
{ currentPassword, newPassword },
|
||||
{ token }
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
<Callout>
|
||||
This documentation comes from the [Convex documentation](https://convex-better-auth.netlify.app/),
|
||||
for more information, please refer to their documentation.
|
||||
</Callout>
|
||||
Reference in New Issue
Block a user