Skip to content

Commit bcc2118

Browse files
doc: add better Auth integration (#468)
* doc: add better Auth integration * resolve code rabbit comments * Update docs/quick-start/authentication/better-auth.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Revert "Update docs/quick-start/authentication/better-auth.md" This reverts commit af26de9. --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
1 parent f2b6059 commit bcc2118

File tree

5 files changed

+133
-4
lines changed

5 files changed

+133
-4
lines changed

docs/quick-start/authentication/auth0.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
description: Integrating with Auth0.
3-
sidebar_position: 6
3+
sidebar_position: 5
44
sidebar_label: Auth0
55
---
66

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
---
2+
description: Integrating with Better Auth
3+
sidebar_position: 2
4+
sidebar_label: Better Auth
5+
---
6+
7+
# Integrating With Better Auth
8+
9+
[Better Auth](https://better-auth.com/) is an emerging open-source TypeScript authentication framework that offers a comprehensive set of features and great extensibility.
10+
11+
## Preparation
12+
13+
Follow Better Auth's installation [guide](https://www.better-auth.com/docs/installation#configure-database) using the Prisma adapter:
14+
15+
```tsx
16+
import { betterAuth } from "better-auth";
17+
import { prismaAdapter } from "better-auth/adapters/prisma";
18+
import { PrismaClient } from "@prisma/client";
19+
20+
const prisma = new PrismaClient();
21+
export const auth = betterAuth({
22+
database: prismaAdapter(prisma, {
23+
provider: "sqlite", // or "mysql", "postgresql", ...etc
24+
}),
25+
});
26+
```
27+
28+
Running Better Auth CLI to generate the Auth-related model in the Prisma schema:
29+
30+
```bash
31+
npx @better-auth/cli generate
32+
```
33+
34+
## Integrate with ZenStack
35+
36+
Follow the [installation guide](https://zenstack.dev/docs/install) to install ZenStack in your project.
37+
38+
Integration with ZenStack is all about obtaining the user's identity and utilizing it to create an enhanced `PrismaClient`. On the server side, Better Auth exposes that through the `api` object of the `auth` instance. For example, here is how to get that in Next.js:
39+
40+
```tsx
41+
import { betterAuth } from "better-auth";
42+
import { headers } from "next/headers";
43+
44+
export const auth = betterAuth({
45+
//...
46+
})
47+
48+
// calling get session on the server
49+
const {session} = await auth.api.getSession({
50+
headers: await headers() // some endpoint might require headers
51+
});
52+
53+
// get the userId from session data
54+
const userId = session.userId;
55+
```
56+
57+
Then you can pass it to ZenStack's [`enhance()`](https://zenstack.dev/docs/reference/runtime-api#enhance) API to create an enhanced `PrismaClient` that automatically enforces access policies.
58+
59+
```tsx
60+
const db = enhance(prisma, { user: {id: userId} });
61+
```
62+
63+
## Organization Plugin Support
64+
65+
Better Auth has a powerful plugin system that allows you to add new features that contribute extensions across the entire stack - data model, backend API, and frontend hooks. A good example is the [Organization plugin](https://www.better-auth.com/docs/plugins/organization), which sets the foundation for implementing multi-tenant apps with access control.
66+
67+
After enabling the Organization plugin and running the CLI to generate the additional models and fields in the schema, you can use the code below on the server side to get the organization info together with the user identity:
68+
69+
```tsx
70+
71+
let organizationRole: string | undefined = undefined;
72+
const organizationId = session.activeOrganizationId;
73+
const org = await auth.api.getFullOrganization({ headers: reqHeaders });
74+
if (org?.members) {
75+
const myMember = org.members.find(
76+
(m) => m.userId === session.userId
77+
);
78+
organizationRole = myMember?.role;
79+
}
80+
81+
// user identity with organization info
82+
const userContext = {
83+
userId: session.userId,
84+
organizationId,
85+
organizationRole,
86+
};
87+
```
88+
89+
:::info
90+
The Better Auth CLI will only update the `schema.prisma` file, if you add the Organization plugin after installing the ZenStack, you need to copy the change to `schema.zmodel` too.
91+
:::
92+
93+
Then you can pass the full `userContext` object to the `enhanced` client:
94+
95+
```tsx
96+
const db = enhance(prisma, { user: userContext });
97+
```
98+
99+
The user context will be accessible in ZModel policy rules via the special `auth()` function. To get it to work, let's add a type in ZModel to define the shape of `auth()`:
100+
101+
```tsx
102+
type Auth {
103+
userId String @id
104+
organizationId String?
105+
organizationRole String?
106+
@@auth
107+
}
108+
```
109+
110+
Here is how you could access it in the access policies:
111+
112+
```tsx
113+
model ToDo {
114+
...
115+
organization Organization? @relation(fields: [organizationId], references: [id], onDelete: Cascade)
116+
organizationId String? @default(auth().organizationId) @allow('update', false)
117+
118+
// deny access that don't belong to the user's active organization
119+
@@deny('all', auth().organizationId != organizationId)
120+
121+
// full access to: list owner, org owner, and org admins
122+
@@allow('all',
123+
auth().userId == ownerId ||
124+
auth().organizationRole == 'owner' ||
125+
auth().organizationRole == 'admin')
126+
}
127+
```
128+
129+
You can find a complete sample of a multi-tenant Todo app code [here](https://github.com/ymc9/better-auth-zenstack-multitenancy).

docs/quick-start/authentication/clerk.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
description: Integrating with Clerk.
3-
sidebar_position: 2
3+
sidebar_position: 3
44
sidebar_label: Clerk
55
---
66

docs/quick-start/authentication/lucia.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
description: Integrating with Lucia.
3-
sidebar_position: 5
3+
sidebar_position: 6
44
sidebar_label: Lucia
55
---
66

docs/quick-start/authentication/supabase.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
description: Integrating with Supabase Auth.
3-
sidebar_position: 3
3+
sidebar_position: 4
44
sidebar_label: Supabase Auth
55
---
66

0 commit comments

Comments
 (0)