From 018038032dd6bc46426dfc7575e274edb1e25107 Mon Sep 17 00:00:00 2001 From: jiasheng Date: Sat, 28 Jun 2025 16:56:26 +0800 Subject: [PATCH 1/4] doc: add better Auth integration --- docs/quick-start/authentication/auth0.md | 2 +- .../quick-start/authentication/better-auth.md | 129 ++++++++++++++++++ docs/quick-start/authentication/clerk.md | 2 +- docs/quick-start/authentication/lucia.md | 2 +- docs/quick-start/authentication/supabase.md | 2 +- 5 files changed, 133 insertions(+), 4 deletions(-) create mode 100644 docs/quick-start/authentication/better-auth.md diff --git a/docs/quick-start/authentication/auth0.md b/docs/quick-start/authentication/auth0.md index 9d790932..7b4ed9b6 100644 --- a/docs/quick-start/authentication/auth0.md +++ b/docs/quick-start/authentication/auth0.md @@ -1,6 +1,6 @@ --- description: Integrating with Auth0. -sidebar_position: 6 +sidebar_position: 5 sidebar_label: Auth0 --- diff --git a/docs/quick-start/authentication/better-auth.md b/docs/quick-start/authentication/better-auth.md new file mode 100644 index 00000000..6cbf5003 --- /dev/null +++ b/docs/quick-start/authentication/better-auth.md @@ -0,0 +1,129 @@ +--- +description: Integrating with Better Auth +sidebar_position: 2 +sidebar_label: Better Auth +--- + +# Integrating With Better Auth + +[Better Auth](https://better-auth.com/) is an emerging open-source TypeScript authentication framework that offers a comprehensive set of features and great extensibility. + +## Preparation + +Follow Better Auth's installation [guide](https://www.better-auth.com/docs/installation#configure-database) using the Prisma adapter: + +```tsx +import { betterAuth } from "better-auth"; +import { prismaAdapter } from "better-auth/adapters/prisma"; +import { PrismaClient } from "@prisma/client"; + +const prisma = new PrismaClient(); +export const auth = betterAuth({ + database: prismaAdapter(prisma, { + provider: "sqlite", // or "mysql", "postgresql", ...etc + }), +}); +``` + +Running Better Auth CLI to generate the Auth-related model in the Prisma schema: + +```bash +npx @better-auth/cli generate +``` + +## Integrate with ZenStack + +Follow the [installation guide](https://zenstack.dev/docs/install) to install ZenStack in your project. + +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 `api` object of the `auth` instance. For example, here is how to get that in Next.js: + +```tsx +import { betterAuth } from "better-auth"; +import { headers } from "next/headers"; + +export const auth = betterAuth({ + //... +}) + +// calling get session on the server +const {session} = await auth.api.getSession({ + headers: await headers() // some endpoint might require headers +}); + +// get the userId from session data +const userId = session.userId; +``` + +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. + +```tsx +const db = enhance(prisma, { user: {id: userId} }); +``` + +## Organization Plugin Support + +Better Auth has a powerful plugin system 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. + +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: + +```tsx + + let organizationRole: string | undefined = undefined; + const organizationId = session.activeOrganizationId; + const org = await auth.api.getFullOrganization({ headers: reqHeaders }); + if (org?.members) { + const myMember = org.members.find( + (m) => m.userId === session.userId + ); + organizationRole = myMember?.role; + } + + // user identiy with organization info + const userContext = { + userId: session.userId, + organizationId, + organizationRole, + }; +``` + +:::info +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. +::: + +Then you could pass this whole user context info to the `enhanced` client: + +```tsx +const db = enhance(prisma, { user: userContext }); +``` + +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()`: + +```tsx +type Auth { + userId String @id + organizationId String? + organizationRole String? + @@auth +} +``` + +Here is how you could access it in the access policies: + +```tsx +model ToDo { + ... + organization Organization? @relation(fields: [organizationId], references: [id], onDelete: Cascade) + organizationId String? @default(auth().organizationId) @allow('update', false) + + // deny access that don't belong to the user's active organization + @@deny('all', auth().organizationId != organizationId) + + // full access to: list owner, org owner, and org admins + @@allow('all', + auth().userId == ownerId || + auth().organizationRole == 'owner' || + auth().organizationRole == 'admin') +} +``` + +You can find a complete sample of a multi-tenant Todo app code [here](https://github.com/ymc9/better-auth-zenstack-multitenancy). \ No newline at end of file diff --git a/docs/quick-start/authentication/clerk.md b/docs/quick-start/authentication/clerk.md index 239a6753..7adafed7 100644 --- a/docs/quick-start/authentication/clerk.md +++ b/docs/quick-start/authentication/clerk.md @@ -1,6 +1,6 @@ --- description: Integrating with Clerk. -sidebar_position: 2 +sidebar_position: 3 sidebar_label: Clerk --- diff --git a/docs/quick-start/authentication/lucia.md b/docs/quick-start/authentication/lucia.md index 84563958..7310c476 100644 --- a/docs/quick-start/authentication/lucia.md +++ b/docs/quick-start/authentication/lucia.md @@ -1,6 +1,6 @@ --- description: Integrating with Lucia. -sidebar_position: 5 +sidebar_position: 6 sidebar_label: Lucia --- diff --git a/docs/quick-start/authentication/supabase.md b/docs/quick-start/authentication/supabase.md index 67ad5194..7d1be034 100644 --- a/docs/quick-start/authentication/supabase.md +++ b/docs/quick-start/authentication/supabase.md @@ -1,6 +1,6 @@ --- description: Integrating with Supabase Auth. -sidebar_position: 3 +sidebar_position: 4 sidebar_label: Supabase Auth --- From b09225ede0ccaa2162c7aef75ddcae49e8fe5764 Mon Sep 17 00:00:00 2001 From: jiasheng Date: Sat, 28 Jun 2025 17:05:35 +0800 Subject: [PATCH 2/4] resolve code rabbit comments --- docs/quick-start/authentication/better-auth.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/quick-start/authentication/better-auth.md b/docs/quick-start/authentication/better-auth.md index 6cbf5003..f5c53c62 100644 --- a/docs/quick-start/authentication/better-auth.md +++ b/docs/quick-start/authentication/better-auth.md @@ -35,7 +35,7 @@ npx @better-auth/cli generate Follow the [installation guide](https://zenstack.dev/docs/install) to install ZenStack in your project. -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 `api` object of the `auth` instance. For example, here is how to get that in Next.js: +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: ```tsx import { betterAuth } from "better-auth"; @@ -62,7 +62,7 @@ const db = enhance(prisma, { user: {id: userId} }); ## Organization Plugin Support -Better Auth has a powerful plugin system 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. +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. 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: @@ -78,7 +78,7 @@ After enabling the Organization plugin and running the CLI to generate the addit organizationRole = myMember?.role; } - // user identiy with organization info + // user identity with organization info const userContext = { userId: session.userId, organizationId, @@ -90,7 +90,7 @@ After enabling the Organization plugin and running the CLI to generate the addit 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. ::: -Then you could pass this whole user context info to the `enhanced` client: +Then you can pass the full `userContext` object to the `enhanced` client: ```tsx const db = enhance(prisma, { user: userContext }); From af26de9cb6b5b62cafaa1df01e3fdb0bdc00d197 Mon Sep 17 00:00:00 2001 From: Jiasheng Date: Sat, 28 Jun 2025 17:10:02 +0800 Subject: [PATCH 3/4] Update docs/quick-start/authentication/better-auth.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .../quick-start/authentication/better-auth.md | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/docs/quick-start/authentication/better-auth.md b/docs/quick-start/authentication/better-auth.md index f5c53c62..09d533a7 100644 --- a/docs/quick-start/authentication/better-auth.md +++ b/docs/quick-start/authentication/better-auth.md @@ -37,22 +37,27 @@ Follow the [installation guide](https://zenstack.dev/docs/install) to install 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: -```tsx import { betterAuth } from "better-auth"; import { headers } from "next/headers"; - +import { PrismaClient } from "@prisma/client"; +import { enhance } from "@zenstackhq/runtime"; + +const prisma = new PrismaClient(); + export const auth = betterAuth({ //... -}) - +}); + // calling get session on the server -const {session} = await auth.api.getSession({ - headers: await headers() // some endpoint might require headers +const { session } = await auth.api.getSession({ + headers: headers(), // some endpoints might require headers }); // get the userId from session data const userId = session.userId; -``` + +// create the enhanced client +const db = enhance(prisma, { user: { id: userId } }); 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. From 910fd042509ea2468f35f1a1aede3a5542cd25bf Mon Sep 17 00:00:00 2001 From: jiasheng Date: Sat, 28 Jun 2025 17:13:05 +0800 Subject: [PATCH 4/4] Revert "Update docs/quick-start/authentication/better-auth.md" This reverts commit af26de9cb6b5b62cafaa1df01e3fdb0bdc00d197. --- .../quick-start/authentication/better-auth.md | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/docs/quick-start/authentication/better-auth.md b/docs/quick-start/authentication/better-auth.md index 09d533a7..f5c53c62 100644 --- a/docs/quick-start/authentication/better-auth.md +++ b/docs/quick-start/authentication/better-auth.md @@ -37,27 +37,22 @@ Follow the [installation guide](https://zenstack.dev/docs/install) to install 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: +```tsx import { betterAuth } from "better-auth"; import { headers } from "next/headers"; -import { PrismaClient } from "@prisma/client"; -import { enhance } from "@zenstackhq/runtime"; - -const prisma = new PrismaClient(); - + export const auth = betterAuth({ //... -}); - +}) + // calling get session on the server -const { session } = await auth.api.getSession({ - headers: headers(), // some endpoints might require headers +const {session} = await auth.api.getSession({ + headers: await headers() // some endpoint might require headers }); // get the userId from session data const userId = session.userId; - -// create the enhanced client -const db = enhance(prisma, { user: { id: userId } }); +``` 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.