组织管理

组织功能简化了用户访问和权限管理。通过分配角色和权限,可以简化项目管理、团队协作和合作伙伴关系。

安装

将插件添加到 auth 配置中

auth.ts
import { betterAuth } from "better-auth"
import { organization } from "better-auth/plugins"

export const auth = betterAuth({
    plugins: [ 
        organization() 
    ] 
})

迁移数据库

运行迁移或生成模式,将必要的字段和表添加到数据库中。

npx @better-auth/cli migrate
npx @better-auth/cli generate

查看 Schema 部分以手动添加字段。

添加客户端插件

auth-client.ts
import { createAuthClient } from "better-auth/client"
import { organizationClient } from "better-auth/client/plugins"

export const authClient = createAuthClient({
    plugins: [ 
        organizationClient() 
    ] 
})

使用

安装插件后,您就可以开始使用组织插件来管理组织的成员和团队。客户端插件将在 organization 命名空间下提供方法。服务器 api 将提供必要的端点来管理您的组织,并为您提供更简便的方式在您自己的后端调用这些功能。

组织

创建组织

POST
/organization/create
const metadata = { someKey: "someValue" };const { data, error } = await authClient.organization.create({    name: "My Organization", // required    slug: "my-org", // required    logo: "https://example.com/logo.png",    metadata,    keepCurrentActiveOrganization: false,});
属性描述类型
name
组织名称。
string
slug
组织标识符。
string
logo?
组织logo。
string
metadata?
组织元数据。
Record<string, any>
keepCurrentActiveOrganization?
创建新组织后是否保持当前活跃组织为活跃状态。
boolean

限制可创建组织的用户

默认情况下,任何用户都可以创建组织。要限制此功能,请将 allowUserToCreateOrganization 选项设置为返回布尔值的函数,或直接设置为 truefalse

auth.ts
import { betterAuth } from "better-auth"
import { organization } from "better-auth/plugins"

const auth = betterAuth({
    //...
    plugins: [
        organization({
            allowUserToCreateOrganization: async (user) => { 
                const subscription = await getSubscription(user.id) 
                return subscription.plan === "pro"
            } 
        })
    ]
})

检查组织别名是否被占用

要检查组织别名是否已被占用,您可以使用客户端提供的 checkSlug 函数。该函数接收一个包含以下属性的对象:

POST
/organization/check-slug
const { data, error } = await authClient.organization.checkSlug({    slug: "my-org", // required});
属性描述类型
slug
要检查的组织别名。
string

组织创建钩子

您可以使用在组织创建前后运行的钩子来自定义组织创建流程。

auth.ts
import { betterAuth } from "better-auth"
import { organization } from "better-auth/plugins"

export const auth = betterAuth({
    plugins: [
        organization({
            organizationCreation: {
                disabled: false, // 设置为 true 可禁用组织创建
                beforeCreate: async ({ organization, user }, request) => {
                    // 在组织创建前运行自定义逻辑
                    // 可选地修改组织数据
                    return {
                        data: {
                            ...organization,
                            metadata: {
                                customField: "value"
                            }
                        }
                    }
                },
                afterCreate: async ({ organization, member, user }, request) => {
                    // 在组织创建后运行自定义逻辑
                    // 例如:创建默认资源、发送通知
                    await setupDefaultResources(organization.id)
                }
            }
        })
    ]
})

beforeCreate 钩子在组织创建前运行。它接收以下参数:

  • organization:组织数据(不包含 ID)
  • user:创建组织的用户
  • request:HTTP 请求对象(可选)

返回包含 data 属性的对象以修改将要创建的组织数据。

afterCreate 钩子在组织成功创建后运行。它接收以下参数:

  • organization:已创建的组织(包含 ID)
  • member:创建者的成员记录
  • user:创建组织的用户
  • request:HTTP 请求对象(可选)

列出用户所属组织

要列出用户所属的组织,您可以使用 useListOrganizations 钩子。它提供了一种响应式的方式来获取用户所属的组织信息。

client.tsx
import { authClient } from "@/lib/auth-client"

function App(){
    const { data: organizations } = authClient.useListOrganizations()
    return (
        <div>
            {organizations.map(org => <p>{org.name}</p>)}
        </div>
    )
}
page.svelte
<script lang="ts">
  import { authClient } from "$lib/auth-client";
  const organizations = authClient.useListOrganizations();
</script>

<h1>组织列表</h1>

{#if $organizations.isPending}
  <p>加载中...</p>
{:else if $organizations.data === null}
  <p>未找到任何组织。</p>
{:else}
  <ul>
    {#each $organizations.data as organization}
      <li>{organization.name}</li>
    {/each}
  </ul>
{/if}
organization.vue
<script lang="ts">;
export default {
    setup() {
        const organizations = authClient.useListOrganizations()
        return { organizations };
    }
};
</script>

<template>
    <div>
        <h1>组织列表</h1>
        <div v-if="organizations.isPending">加载中...</div>
        <div v-else-if="organizations.data === null">未找到任何组织。</div>
        <ul v-else>
            <li v-for="organization in organizations.data" :key="organization.id">
                {{ organization.name }}
            </li>
        </ul>
    </div>
</template>

或者,如果您不想使用钩子,也可以直接调用 organization.list 接口。

GET
/organization/list
const { data, error } = await authClient.organization.list();

当前活跃组织

当前活跃组织是指用户正在使用的工作空间。默认情况下,当用户登录时,当前活跃组织设置为 null。您可以在用户会话中设置当前活跃组织。

并非所有情况下都需要在会话中持久化当前活跃组织。您可以仅在客户端管理当前活跃组织。例如,多个标签页可以有不同的活跃组织。

设置当前活跃组织

您可以通过调用 organization.setActive 函数来设置当前活跃组织。这将为用户会话设置当前活跃组织。

在某些应用中,您可能需要取消设置当前活跃组织的能力。 这种情况下,您可以将 organizationId 设置为 null 来调用此端点。

POST
/organization/set-active
const { data, error } = await authClient.organization.setActive({    organizationId: "org-id",    organizationSlug: "org-slug",});
属性描述类型
organizationId?
要设置为活跃组织的组织ID。可以为 null 以取消设置当前活跃组织。
string | null
organizationSlug?
要设置为活跃组织的组织别名。如果未提供 organizationId,可以设置为 null 以取消设置当前活跃组织。
string

要在创建会话时设置当前活跃组织,您可以使用数据库钩子

auth.ts
export const auth = betterAuth({
  databaseHooks: {
      session: {
          create: {
              before: async(session)=>{
                  const organization = await getActiveOrganization(session.userId)
                  return {
                    data: {
                      ...session,
                      activeOrganizationId: organization.id
                    }
                  }
              }
          }
      }
  }
})

使用当前组织

要获取用户的当前组织,您可以调用 useActiveOrganization 钩子。它会返回用户的当前组织。当当前组织发生变化时,钩子将重新评估并返回新的当前组织。

client.tsx
import { authClient } from "@/lib/auth-client"

function App(){
    const { data: activeOrganization } = authClient.useActiveOrganization()
    return (
        <div>
            {activeOrganization ? <p>{activeOrganization.name}</p> : null}
        </div>
    )
}
client.tsx
<script lang="ts">
import { authClient } from "$lib/auth-client";
const activeOrganization = authClient.useActiveOrganization();
</script>

<h2>当前组织</h2>

{#if $activeOrganization.isPending}
<p>加载中...</p>
{:else if $activeOrganization.data === null}
<p>未找到当前组织。</p>
{:else}
<p>{$activeOrganization.data.name}</p>
{/if}
organization.vue
<script lang="ts">;
export default {
    setup() {
        const activeOrganization = authClient.useActiveOrganization();
        return { activeOrganization };
    }
};
</script>

<template>
    <div>
        <h2>当前组织</h2>
        <div v-if="activeOrganization.isPending">加载中...</div>
        <div v-else-if="activeOrganization.data === null">无当前组织。</div>
        <div v-else>
            {{ activeOrganization.data.name }}
        </div>
    </div>
</template>

获取完整组织信息

要获取组织的完整详细信息,您可以使用 getFullOrganization 函数。 默认情况下,如果您不传递任何参数,它将使用当前活跃的组织。

GET
/organization/get-full-organization
const { data, error } = await authClient.organization.getFullOrganization({    organizationId: "org-id",    organizationSlug: "org-slug",    membersLimit: 100,});
属性描述类型
organizationId?
要获取的组织ID。默认情况下,将使用当前活跃的组织。
string
organizationSlug?
要获取的组织slug。
string
membersLimit?
要获取的成员数量限制。默认使用 membershipLimit 选项,该选项默认为 100。
number

更新组织信息

要更新组织信息,您可以使用 organization.update

POST
/organization/update
const { data, error } = await authClient.organization.update({    data: { // required        name: "updated-name",        slug: "updated-slug",        logo: "new-logo.url",        metadata: { customerId: "test" },    },    organizationId: "org-id",});
属性描述类型
data
用于更新组织的部分数据列表。
Object
data.name?
组织的名称。
string
data.slug?
组织的slug。
string
data.logo?
组织的徽标。
string
data.metadata?
组织的元数据。
Record<string, any> | null
organizationId?
要更新的组织ID。
string

删除组织

要删除用户拥有的组织,可以使用 organization.delete 方法

POST
/organization/delete
const { data, error } = await authClient.organization.delete({    organizationId: "org-id", // required});
属性描述类型
organizationId
要删除的组织 ID
string

如果用户在指定组织中拥有必要的权限(默认为:所有者角色),所有成员、邀请信息以及组织信息都将被删除。

您可以通过 organizationDeletion 选项来配置组织删除的处理方式:

const auth = betterAuth({
  plugins: [
    organization({
      organizationDeletion: {
        disabled: true, // 完全禁用删除功能
        beforeDelete: async (data, request) => {
          // 删除组织前执行的回调函数
        },
        afterDelete: async (data, request) => {
          // 删除组织后执行的回调函数
        },
      },
    }),
  ],
});

邀请管理

要将成员添加到组织,首先需要向用户发送邀请。用户将通过邮件/短信收到邀请链接。一旦用户接受邀请,他们将被添加到组织中。

设置邀请邮件

要使成员邀请功能正常工作,我们首先需要为 better-auth 实例提供 sendInvitationEmail 函数。该函数负责向用户发送邀请邮件。

您需要构建邀请链接并将其发送给用户。该链接应包含邀请 ID,当用户点击链接时,该 ID 将与 acceptInvitation 函数一起使用。

auth.ts
import { betterAuth } from "better-auth"
import { organization } from "better-auth/plugins"
import { sendOrganizationInvitation } from "./email"
export const auth = betterAuth({
	plugins: [
		organization({
			async sendInvitationEmail(data) {
        const inviteLink = `https://example.com/accept-invitation/${data.id}`
				sendOrganizationInvitation({
					  email: data.email,
						invitedByUsername: data.inviter.user.name,
						invitedByEmail: data.inviter.user.email,
						teamName: data.organization.name,
						inviteLink
				})
			},
		}),
	],
});

发送邀请

要邀请用户加入组织,您可以使用客户端提供的 invite 函数。该函数接收一个包含以下属性的对象:

POST
/organization/invite-member
const { data, error } = await authClient.organization.inviteMember({    email: "example@gmail.com", // required    role: "member", // required    organizationId: "org-id",    resend: true,    teamId: "team-id",});
属性描述类型
email
被邀请用户的邮箱地址。
string
role
分配给用户的角色。可以是 adminmemberguest
string | string[]
organizationId?
邀请用户加入的组织 ID。默认为当前活跃组织。
string
resend?
如果用户已被邀请,是否重新发送邀请邮件。
boolean
teamId?
邀请用户加入的团队 ID。
string
  • 如果用户已是组织成员,邀请将被取消。
  • 如果用户已被邀请到该组织,除非 resend 设为 true,否则不会再次发送邀请。
  • 如果 cancelPendingInvitationsOnReInvite 设为 true,当用户已被邀请到组织时,原邀请将被取消并发送新邀请。

接受邀请

当用户收到邀请邮件后,可以点击邀请链接接受邀请。邀请链接应包含邀请 ID,该 ID 将用于接受邀请。

请确保在用户登录后调用 acceptInvitation 函数。

POST
/organization/accept-invitation
const { data, error } = await authClient.organization.acceptInvitation({    invitationId: "invitation-id", // required});
属性描述类型
invitationId
要接受的邀请 ID。
string

邮箱验证要求

如果在组织配置中启用了 requireEmailVerificationOnInvitation 选项,用户在接受邀请前必须验证其邮箱地址。这增加了一层额外的安全保护,确保只有经过验证的用户才能加入您的组织。

auth.ts
import { betterAuth } from "better-auth"
import { organization } from "better-auth/plugins"

export const auth = betterAuth({
    plugins: [
        organization({
            requireEmailVerificationOnInvitation: true, 
            async sendInvitationEmail(data) {
                // ... 您的邮件发送逻辑
            }
        })
    ]
})

邀请接受回调

您可以配置 Better Auth,在邀请被接受时执行回调函数。这对于记录事件、更新分析、发送通知,或任何其他在有人加入组织时需要运行的自定义逻辑非常有用。

auth.ts
import { betterAuth } from "better-auth"
import { organization } from "better-auth/plugins"

export const auth = betterAuth({
	plugins: [
		organization({
			async sendInvitationEmail(data) {
				// ... 您的邀请邮件逻辑
			},
			async onInvitationAccepted(data) {
				// 当邀请被接受时,此回调会被触发
			},
		}),
	],
});

回调函数会接收到以下数据:

  • id: 邀请 ID
  • role: 分配给用户的角色
  • organization: 用户加入的组织
  • invitation: 邀请对象
  • inviter: 发送邀请的成员(包含用户详细信息)
  • acceptedUser: 接受邀请的用户

取消邀请

如果用户已发出邀请,可以使用此方法取消该邀请。

如果您想了解用户如何拒绝邀请,请查看此处

POST
/organization/cancel-invitation
await authClient.organization.cancelInvitation({    invitationId: "invitation-id", // required});
属性描述类型
invitationId
要取消的邀请ID
string

拒绝邀请

如果用户收到了邀请但希望拒绝,此方法允许用户通过拒绝邀请来实现。

POST
/organization/reject-invitation
await authClient.organization.rejectInvitation({    invitationId: "invitation-id", // required});
属性描述类型
invitationId
要拒绝的邀请ID
string

与接受邀请类似,当启用 requireEmailVerificationOnInvitation 选项时,拒绝邀请也需要进行邮箱验证。邮箱未验证的用户在尝试拒绝邀请时会收到错误提示。

获取邀请

要获取邀请信息,可以使用客户端提供的 organization.getInvitation 函数。您需要将邀请ID作为查询参数提供。

GET
/organization/get-invitation
const { data, error } = await authClient.organization.getInvitation({    id: "invitation-id", // required});
属性描述类型
id
要获取的邀请ID
string

列出邀请

要列出给定组织的所有邀请,可以使用客户端提供的 listInvitations 函数。

GET
/organization/list-invitations
const { data, error } = await authClient.organization.listInvitations({    organizationId: "organization-id",});
属性描述类型
organizationId?
可选的组织ID,用于列出该组织的邀请。如果未提供,将默认使用用户的当前活跃组织。
string

列出用户邀请

要列出指定用户的所有邀请,您可以使用客户端提供的 listUserInvitations 函数。

auth-client.ts
const invitations = await authClient.organization.listUserInvitations()

在服务器端,您可以将用户 ID 作为查询参数传递。

api.ts
const invitations = await auth.api.listUserInvitations({
    query: {
        email: "user@example.com"
    }
})

email 查询参数仅在服务器端可用,用于查询特定用户的邀请。

成员

列出成员

要列出组织的所有成员,您可以使用 listMembers 函数。

GET
/organization/list-members
const { data, error } = await authClient.organization.listMembers({    organizationId: "organization-id",    limit: 100,    offset: 0,    sortBy: "createdAt",    sortDirection: "desc",    filterField: "createdAt",    filterOperator: "eq",    filterValue: "value",});
属性描述类型
organizationId?
可选的 organization ID,用于列出成员。如果未提供,将默认为用户当前活跃的组织。
string
limit?
要返回的成员数量限制。
number
offset?
起始偏移量。
number
sortBy?
排序依据的字段。
string
sortDirection?
排序方向。
"asc" | "desc"
filterField?
筛选依据的字段。
string
filterOperator?
筛选操作符。
"eq" | "ne" | "gt" | "gte" | "lt" | "lte" | "in" | "nin" | "contains"
filterValue?
筛选值。
string

移除成员

您可以使用 organization.removeMember 来移除成员

POST
/organization/remove-member
const { data, error } = await authClient.organization.removeMember({    memberIdOrEmail: "user@example.com", // required    organizationId: "org-id",});
属性描述类型
memberIdOrEmail
要移除的成员的ID或邮箱。
string
organizationId?
要从中移除成员的组织ID。如果未提供,将使用当前活跃组织。
string

更新成员角色

要更新组织中成员的角色,您可以使用 organization.updateMemberRole。如果用户有权限更新该成员的角色,角色将被更新。

POST
/organization/update-member-role
await authClient.organization.updateMemberRole({    role: ["admin", "sale"], // required    memberId: "member-id", // required    organizationId: "organization-id",});
属性描述类型
role
要应用的新角色。可以是字符串或字符串数组,表示角色。
string | string[]
memberId
要应用角色更新的成员ID。
string
organizationId?
成员所属的可选组织ID,用于应用角色更新。如果未提供,您必须提供会话头信息以获取当前活跃组织。
string

获取当前活跃成员

要获取当前活跃组织的成员信息,您可以使用 organization.getActiveMember 函数。此函数将返回用户在其当前活跃组织中的成员详细信息。

GET
/organization/get-active-member
const { data: member, error } = await authClient.organization.getActiveMember();

添加成员

如果您想直接将成员添加到组织而不发送邀请,可以使用 addMember 函数,该函数只能在服务器端调用。

POST
/organization/add-member
const data = await auth.api.addMember({    body: {        userId: "user-id",        role: ["admin", "sale"], // required        organizationId: "org-id",        teamId: "team-id",    },});
属性描述类型
userId?
要添加为成员的用户 ID。如果提供 null,则需要提供会话头信息。
string | null
role
分配给新成员的角色。
string | string[]
organizationId?
可选的传递的组织 ID。如果未提供,将默认为用户的当前活跃组织。
string
teamId?
可选的团队 ID,用于将成员添加到该团队。
string

离开组织

要离开组织,您可以使用 organization.leave 函数。此函数将从组织中移除当前用户。

POST
/organization/leave
await authClient.organization.leave({    organizationId: "organization-id", // required});
属性描述类型
organizationId
成员要离开的组织 ID。
string

访问控制

组织插件提供了一个非常灵活的访问控制系统。您可以根据用户在组织中的角色来控制其访问权限。您可以根据用户的角色定义自己的权限集。

角色

默认情况下,组织中有三种角色:

owner(所有者):默认创建组织的用户。所有者对组织拥有完全控制权,可以执行任何操作。

admin(管理员):拥有管理员角色的用户对组织拥有完全控制权,但不能删除组织或更改所有者。

member(成员):拥有成员角色的用户对组织的控制权有限。他们可以创建项目、邀请用户以及管理自己创建的项目。

一个用户可以拥有多个角色。多个角色以逗号(",")分隔的字符串形式存储。

权限

默认情况下,有三种资源,每种资源有两到三个操作。

organization(组织)

update(更新) delete(删除)

member(成员)

create(创建) update(更新) delete(删除)

invitation(邀请)

create(创建) cancel(取消)

所有者对所有资源和操作拥有完全控制权。管理员对所有资源拥有完全控制权,但不能删除组织或更改所有者。成员除了读取数据外,对这些操作没有任何控制权。

自定义权限

该插件提供了一种简单的方式,为每个角色定义您自己的权限集。

创建访问控制

您首先需要通过调用 createAccessControl 函数并传递声明对象来创建访问控制器。声明对象应以资源名称作为键,以操作数组作为值。

permissions.ts
import { createAccessControl } from "better-auth/plugins/access";

/**
 * 确保使用 `as const`,以便 TypeScript 能正确推断类型
 */
const statement = { 
    project: ["create", "share", "update", "delete"], 
} as const; 

const ac = createAccessControl(statement); 

创建角色

创建访问控制器后,您可以使用已定义的权限创建角色。

permissions.ts
import { createAccessControl } from "better-auth/plugins/access";

const statement = {
    project: ["create", "share", "update", "delete"],
} as const;

const ac = createAccessControl(statement);

const member = ac.newRole({ 
    project: ["create"], 
}); 

const admin = ac.newRole({ 
    project: ["create", "update"], 
}); 

const owner = ac.newRole({ 
    project: ["create", "update", "delete"], 
}); 

const myCustomRole = ac.newRole({ 
    project: ["create", "update", "delete"], 
    organization: ["update"], 
}); 

当您为现有角色创建自定义角色时,这些角色的预定义权限将被覆盖。要将现有权限添加到自定义角色中,您需要导入 defaultStatements 并将其与您的新声明合并,同时将角色的权限集与默认角色合并。

permissions.ts
import { createAccessControl } from "better-auth/plugins/access";
import { defaultStatements, adminAc } from 'better-auth/plugins/organization/access'

const statement = {
    ...defaultStatements, 
    project: ["create", "share", "update", "delete"],
} as const;

const ac = createAccessControl(statement);

const admin = ac.newRole({
    project: ["create", "update"],
    ...adminAc.statements, 
});

将角色传递给插件

创建角色后,您可以将它们传递给客户端和服务器的组织插件。

auth.ts
import { betterAuth } from "better-auth"
import { organization } from "better-auth/plugins"
import { ac, owner, admin, member } from "@/auth/permissions"

export const auth = betterAuth({
    plugins: [
        organization({
            ac,
            roles: {
                owner,
                admin,
                member,
                myCustomRole
            }
        }),
    ],
});

您还需要将访问控制器和角色传递给客户端插件。

auth-client
import { createAuthClient } from "better-auth/client"
import { organizationClient } from "better-auth/client/plugins"
import { ac, owner, admin, member, myCustomRole } from "@/auth/permissions"

export const authClient = createAuthClient({
    plugins: [
        organizationClient({
            ac,
            roles: {
                owner,
                admin,
                member,
                myCustomRole
            }
        })
  ]
})

访问控制使用

权限检查:

您可以使用 api 提供的 hasPermission 操作来检查用户的权限。

api.ts
import { auth } from "@/auth";

await auth.api.hasPermission({
  headers: await headers(),
    body: {
      permissions: {
        project: ["create"] // 这必须与您的访问控制结构匹配
      }
    }
});

// 您也可以同时检查多个资源权限
await auth.api.hasPermission({
  headers: await headers(),
    body: {
      permissions: {
        project: ["create"], // 这必须与您的访问控制结构匹配
        sale: ["create"]
      }
    }
});

如果您想从服务器端检查客户端用户的权限,可以使用客户端提供的 hasPermission 函数。

auth-client.ts
const canCreateProject = await authClient.organization.hasPermission({
    permissions: {
        project: ["create"]
    }
})

// 您也可以同时检查多个资源权限
const canCreateProjectAndCreateSale = await authClient.organization.hasPermission({
    permissions: {
        project: ["create"],
        sale: ["create"]
    }
})

检查角色权限:

一旦您定义了角色和权限,为了避免从服务器检查权限,您可以使用客户端提供的 checkRolePermission 函数。

auth-client.ts
const canCreateProject = authClient.organization.checkRolePermission({
	permissions: {
		organization: ["delete"],
	},
	role: "admin",
});

// 您也可以同时检查多个资源权限
const canCreateProjectAndCreateSale = authClient.organization.checkRolePermission({
	permissions: {
		organization: ["delete"],
    member: ["delete"]
	},
	role: "admin",
});

团队功能

团队功能允许您在组织内对成员进行分组。团队功能提供了额外的组织结构,可用于在更细粒度的级别上管理权限。

启用团队功能

要启用团队功能,请将 teams 配置选项传递给服务器和客户端插件:

auth.ts
import { betterAuth } from "better-auth"
import { organization } from "better-auth/plugins"

export const auth = betterAuth({
    plugins: [
        organization({
            teams: {
                enabled: true,
                maximumTeams: 10, // 可选:限制每个组织的团队数量
                allowRemovingAllTeams: false // 可选:防止删除最后一个团队
            }
        })
    ]
})
auth-client.ts
import { createAuthClient } from "better-auth/client"
import { organizationClient } from "better-auth/client/plugins"

export const authClient = createAuthClient({
    plugins: [
        organizationClient({
            teams: {
                enabled: true
            }
        })
    ]
})

管理团队

创建团队

在组织内创建一个新团队:

POST
/organization/create-team
const { data, error } = await authClient.organization.createTeam({    name: "my-team", // required    organizationId: "organization-id",});
属性描述类型
name
团队名称。
string
organizationId?
将在其中创建团队的组织 ID。默认为当前活跃组织。
string

列出团队

获取组织中的所有团队:

GET
/organization/list-teams
const { data, error } = await authClient.organization.listTeams({    organizationId: "organziation-id",});
属性描述类型
organizationId?
要列出团队的组织 ID。默认为用户的当前活跃组织。
string

更新团队

更新团队的详细信息:

POST
/organization/update-team
const { data, error } = await authClient.organization.updateTeam({    teamId: "team-id", // required    data: { // required        name: "我的新团队名称",        organizationId: "此团队的新组织ID",        createdAt: new Date(),        updatedAt: new Date(),    },});
属性描述类型
teamId
要更新的团队ID。
string
data
包含更新选项的部分对象。
Object
data.name?
要更新的团队名称。
string
data.organizationId?
团队所属的组织ID。
string
data.createdAt?
团队创建的时间戳。
Date
data.updatedAt?
团队最后更新的时间戳。
Date

移除团队

从组织中删除一个团队:

POST
/organization/remove-team
const { data, error } = await authClient.organization.removeTeam({    teamId: "team-id", // required    organizationId: "organization-id",});
属性描述类型
teamId
要移除的团队ID。
string
organizationId?
团队所属的组织ID。如果未提供,将默认为用户的当前活跃组织。
string

设置活跃团队

将指定团队设置为当前活跃团队。如果 teamIdnull,则取消当前活跃团队。

POST
/organization/set-active-team
const { data, error } = await authClient.organization.setActiveTeam({    teamId: "team-id",});
属性描述类型
teamId?
要设置为当前活跃团队的团队ID。
string

列出用户团队

列出当前用户所属的所有团队。

GET
/organization/list-user-teams
const { data, error } = await authClient.organization.listUserTeams();

列出团队成员

获取指定团队成员列表。

POST
/organization/list-team-members
const { data, error } = await authClient.organization.listTeamMembers({    teamId: "team-id",});
属性描述类型
teamId?
需要返回成员的团队ID。如果未提供,则返回当前活跃团队的成员。
string

添加团队成员

向团队中添加成员。

POST
/organization/add-team-member
const { data, error } = await authClient.organization.addTeamMember({    teamId: "team-id", // required    userId: "user-id", // required});
属性描述类型
teamId
用户需要加入的团队ID。
string
userId
需要添加为成员的用户ID。
string

移除团队成员

从团队中移除成员。

POST
/organization/remove-team-member
const { data, error } = await authClient.organization.removeTeamMember({    teamId: "team-id", // required    userId: "user-id", // required});
属性描述类型
teamId
需要移除用户的团队ID。
string
userId
需要从团队中移除的用户ID。
string

团队权限

团队遵循组织的权限系统。要管理团队,用户需要以下权限:

  • team:create - 创建新团队
  • team:update - 更新团队详情
  • team:delete - 删除团队

默认情况下:

  • 组织所有者和管理员可以管理团队
  • 普通成员无法创建、更新或删除团队

团队配置选项

团队功能支持多种配置选项:

  • maximumTeams:限制每个组织的团队数量

    teams: {
      enabled: true,
      maximumTeams: 10 // 固定数量
      // 或
      maximumTeams: async ({ organizationId, session }, request) => {
        // 基于组织计划的动态限制
        const plan = await getPlan(organizationId)
        return plan === 'pro' ? 20 : 5
      },
      maximumMembersPerTeam: 10 // 固定数量
      // 或
      maximumMembersPerTeam: async ({ teamId, session, organizationId }, request) => {
        // 基于团队计划的动态限制
        const plan = await getPlan(organizationId, teamId)
        return plan === 'pro' ? 50 : 10
      },
    }
  • allowRemovingAllTeams:控制是否允许移除最后一个团队

    teams: {
      enabled: true,
      allowRemovingAllTeams: false // 禁止移除最后一个团队
    }

团队成员

邀请成员加入组织时,可以指定团队:

await authClient.organization.inviteMember({
    email: "user@example.com",
    role: "member",
    teamId: "team-id"
})

受邀成员在接受邀请后将被添加到指定的团队中。

数据库结构

启用团队功能后,数据库中将新增 teamteamMember 两张表。

表名:team

字段名称类型Key描述
idstring每个团队的唯一标识符
namestring-团队名称
organizationIdstring所属组织的ID
createdAtDate-团队创建时间戳
updatedAtDate团队最后更新时间戳

表名:teamMember

字段名称类型Key描述
idstring每个团队成员的唯一标识符
teamIdstring所属团队的唯一标识符
userIdstring用户ID
createdAtDate-团队成员创建时间戳

结构

组织插件会向数据库添加以下表:

组织(Organization)

表名:organization

字段名称类型Key描述
idstring每个组织的唯一标识符
namestring-组织的名称
slugstring-组织的 slug
logostring组织的 logo
metadatastring组织的附加元数据
createdAtDate-组织创建的时间戳

成员(Member)

表名:member

字段名称类型Key描述
idstring每个成员的唯一标识符
userIdstring用户的 ID
organizationIdstring组织的 ID
rolestring-用户在组织中的角色
createdAtDate-成员加入组织的时间戳

邀请表

表名: invitation

字段名称类型Key描述
idstring每个邀请的唯一标识符
emailstring-用户的邮箱地址
inviterIdstring邀请者的ID
organizationIdstring组织的ID
rolestring-用户在组织中的角色
statusstring-邀请的状态
expiresAtDate-邀请的过期时间戳

如果启用了团队功能,你需要在邀请表中添加以下字段:

字段名称类型Key描述
teamIdstring团队的ID

会话表

表名: session

你需要在会话表中再添加两个字段,用于存储当前活跃的组织ID和团队ID。

字段名称类型Key描述
activeOrganizationIdstring当前活跃组织的ID
activeTeamIdstring当前活跃团队的ID

团队(可选)

表名:team

字段名称类型Key描述
idstring每个团队的唯一标识符
namestring-团队名称
organizationIdstring所属组织的 ID
createdAtDate-团队创建时间戳
updatedAtDate团队更新时间戳

表名:teamMember

字段名称类型Key描述
idstring每个团队成员的唯一标识符
teamIdstring所属团队的唯一标识符
userIdstring用户的 ID
createdAtDate-团队成员创建时间戳

表名:invitation

字段名称类型Key描述
teamIdstring团队 ID

自定义数据表结构

如需更改数据表名称或字段,您可以将 schema 选项传递给组织插件。

auth.ts
const auth = betterAuth({
  plugins: [
    organization({
      schema: {
        organization: {
          modelName: "organizations",  // 将组织表映射到 organizations
          fields: {
            name: "title" // 将 name 字段映射到 title
          },
          additionalFields: {
            // 向组织表添加新字段
            myCustomField: {
              type: "string",
              input: true,
              required: false
            }
          }
        }
      }
    })
  ]
})

附加字段

Better Auth v1.3 开始,您可以轻松地向 organization(组织)、invitation(邀请)、member(成员)和 team(团队)表添加自定义字段。

当您为模型添加额外字段时,相关的 API 端点将自动接受并返回这些新属性。例如,如果您向 organization 表添加了一个自定义字段,createOrganization 端点将在其请求和响应负载中根据需要包含此字段。

auth.ts
const auth = betterAuth({
  plugins: [
    organization({
      schema: {
        organization: {
          additionalFields: {
            myCustomField: { 
              type: "string", 
              input: true, 
              required: false
            } 
          }
        }
      }
    })
  ]
})

要推断附加字段,您可以使用 inferOrgAdditionalFields 函数。此函数将从 auth 对象类型中推断出附加字段。

auth-client.ts
import { createAuthClient } from "better-auth/client";
import { inferOrgAdditionalFields, organizationClient } from "better-auth/client/plugins";
import type { auth } from "@/auth" // 仅导入 auth 对象类型

const client = createAuthClient({
    plugins: [organizationClient({
        schema: inferOrgAdditionalFields<typeof auth>()
    })]
})

如果您无法导入 auth 对象类型,可以不使用泛型来调用 inferOrgAdditionalFields 函数。此函数将从 schema 对象中推断出附加字段。

auth-client.ts

const client = createAuthClient({
    plugins: [organizationClient({
        schema: inferOrgAdditionalFields({
          organization: { 
            additionalFields: {
              newField: { 
                type: "string", 
              }, 
            },
          },
        })
    })]
})

// 使用示例
await client.organization.create({
    name: "Test",
    slug: "test",
    newField: "123", // 这应该被允许
    //@ts-expect-error - 此字段不可用
    unavalibleField: "123", // 这应该不被允许
})

选项

allowUserToCreateOrganization: boolean | ((user: User) => Promise<boolean> | boolean) - 用于判断用户是否可以创建组织的函数。默认为 true。可设置为 false 以限制用户创建组织。

organizationLimit: number | ((user: User) => Promise<boolean> | boolean) - 用户允许创建的最大组织数量。默认为 5。可设置为任意数字或返回布尔值的函数。

creatorRole: admin | owner - 创建组织的用户角色。默认为 owner。可设置为 admin

membershipLimit: number - 组织中允许的最大成员数量。默认为 100。可设置为任意数字。

sendInvitationEmail: async (data) => Promise<void> - 用于向用户发送邀请邮件的函数。

invitationExpiresIn : number - 邀请链接的有效时长(单位:秒)。默认为 48 小时(2 天)。

cancelPendingInvitationsOnReInvite: boolean - 当用户已被邀请到组织时,是否取消待处理的邀请。默认为 false

invitationLimit: number | ((user: User) => Promise<boolean> | boolean) - 用户允许发送的最大邀请数量。默认为 100。可设置为任意数字或返回布尔值的函数。

requireEmailVerificationOnInvitation: boolean - 在接受或拒绝邀请前是否需要验证邮箱。默认为 false。启用后,用户必须先验证邮箱地址才能接受或拒绝组织邀请。