# 组织 (/docs/plugins/organization)

组织插件允许您管理组织的成员和团队。



组织简化了用户访问和权限管理。分配角色和权限以简化项目管理、团队协调和合作。

## 安装 [#安装]

<Steps>
  <Step>
    ### 将插件添加到您的 **auth** 配置中 [#将插件添加到您的-auth-配置中]

    ```ts title="auth.ts"
    import { betterAuth } from "better-auth"
    import { organization } from "better-auth/plugins" // [!code highlight]

    export const auth = betterAuth({
        plugins: [
            organization() // [!code highlight]
        ]
    })
    ```
  </Step>

  <Step>
    ### 迁移数据库 [#迁移数据库]

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

    <Tabs items="[&#x22;迁移&#x22;, &#x22;生成&#x22;]">
      <Tab value="迁移">
        <CodeBlockTabs defaultValue="npm" groupId="persist-install">
          <CodeBlockTabsList>
            <CodeBlockTabsTrigger value="npm">
              npm
            </CodeBlockTabsTrigger>

            <CodeBlockTabsTrigger value="pnpm">
              pnpm
            </CodeBlockTabsTrigger>

            <CodeBlockTabsTrigger value="yarn">
              yarn
            </CodeBlockTabsTrigger>

            <CodeBlockTabsTrigger value="bun">
              bun
            </CodeBlockTabsTrigger>
          </CodeBlockTabsList>

          <CodeBlockTab value="npm">
            ```bash
            npx auth migrate
            ```
          </CodeBlockTab>

          <CodeBlockTab value="pnpm">
            ```bash
            pnpm dlx auth migrate
            ```
          </CodeBlockTab>

          <CodeBlockTab value="yarn">
            ```bash
            yarn dlx auth migrate
            ```
          </CodeBlockTab>

          <CodeBlockTab value="bun">
            ```bash
            bun x auth migrate
            ```
          </CodeBlockTab>
        </CodeBlockTabs>
      </Tab>

      <Tab value="生成">
        <CodeBlockTabs defaultValue="npm" groupId="persist-install">
          <CodeBlockTabsList>
            <CodeBlockTabsTrigger value="npm">
              npm
            </CodeBlockTabsTrigger>

            <CodeBlockTabsTrigger value="pnpm">
              pnpm
            </CodeBlockTabsTrigger>

            <CodeBlockTabsTrigger value="yarn">
              yarn
            </CodeBlockTabsTrigger>

            <CodeBlockTabsTrigger value="bun">
              bun
            </CodeBlockTabsTrigger>
          </CodeBlockTabsList>

          <CodeBlockTab value="npm">
            ```bash
            npx auth generate
            ```
          </CodeBlockTab>

          <CodeBlockTab value="pnpm">
            ```bash
            pnpm dlx auth generate
            ```
          </CodeBlockTab>

          <CodeBlockTab value="yarn">
            ```bash
            yarn dlx auth generate
            ```
          </CodeBlockTab>

          <CodeBlockTab value="bun">
            ```bash
            bun x auth generate
            ```
          </CodeBlockTab>
        </CodeBlockTabs>
      </Tab>
    </Tabs>

    查看 [Schema](#schema) 部分以手动添加这些字段。
  </Step>

  <Step>
    ### 添加客户端插件 [#添加客户端插件]

    ```ts title="auth-client.ts"
    import { createAuthClient } from "better-auth/client"
    import { organizationClient } from "better-auth/client/plugins" // [!code highlight]

    export const authClient = createAuthClient({
        plugins: [
            organizationClient() // [!code highlight]
        ]
    })
    ```
  </Step>
</Steps>

## 用法 [#用法]

安装插件后，您就可以开始使用组织插件来管理组织的成员和团队。客户端插件会在 `organization` 命名空间下提供方法，服务器端的 `api` 会提供管理组织所需的接口，并让您更轻松地调用后端函数。

## 组织 [#组织]

### 创建组织 [#创建组织]

**Endpoint:** `POST /organization/create`

### Client Side

```ts
const metadata = { someKey: "someValue" };
const { data, error } = await authClient.organization.create({
    name: "我的组织", // required, 组织名称。
    slug: "my-org", // required, 组织短名称。
    logo: "https://example.com/logo.png", // 组织徽标。
    metadata, // 组织的元数据。
    keepCurrentActiveOrganization: false, // 创建新组织后是否保持当前活跃组织仍为活跃状态。
});
```

### Server Side

```ts
const metadata = { someKey: "someValue" };
const data = await auth.api.createOrganization({
    body: {
        name: "我的组织", // required, 组织名称。
        slug: "my-org", // required, 组织短名称。
        logo: "https://example.com/logo.png", // 组织徽标。
        metadata, // 组织的元数据。
        userId: "some_user_id", // server-only, 组织创建者的用户 ID。 如果提供了会话头信息，则会忽略此项。
        keepCurrentActiveOrganization: false, // 创建新组织后是否保持当前活跃组织仍为活跃状态。
    },
    // This endpoint requires session cookies.
    headers: await headers(),
});
```

### Type Definition

```ts
type createOrganization = {
  /**
  * 组织名称。
  */
  name: string = "我的组织"
  /**
  * 组织短名称。
  */
  slug: string = "my-org"
  /**
  * 组织徽标。
  */
  logo?: string | null = "https://example.com/logo.png"
  /**
  * 组织的元数据。
  */
  metadata?: Record<string, any>
  /**
  * 组织创建者的用户 ID。
  * @serverOnly - 如果提供了会话头信息，则会忽略此项。
  */
  userId?: string = "some_user_id"
  /**
  * 创建新组织后是否保持当前活跃组织仍为活跃状态。
  */
  keepCurrentActiveOrganization?: boolean = false
}
```

<Callout type="warn">
  **互斥参数**

  `userId` 和会话头信息不能同时使用：

  * **使用会话头信息时：** 组织会为已认证的会话用户创建。`userId` 字段会被**静默忽略**。
  * **不使用会话头信息时（仅服务端）：** 组织会为 `userId` 指定的用户创建。

  **对于管理员：** 若要代表其他用户创建组织，必须在服务端调用 API，且**不要**传递会话头信息。
</Callout>

#### 限制谁可以创建组织 [#限制谁可以创建组织]

默认情况下，任何用户都可以创建组织。若要限制，设置 `allowUserToCreateOrganization` 选项为返回布尔值的函数，或直接为 `true` 或 `false`。

```ts title="auth.ts"
import { betterAuth } from "better-auth";
import { organization } from "better-auth/plugins";

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

#### 检查组织短名称是否已被占用 [#检查组织短名称是否已被占用]

您可以使用客户端提供的 `checkSlug` 函数检查组织短名称是否已被占用。此函数接受一个包含以下属性的对象：

**Endpoint:** `POST /organization/check-slug`

### Client Side

```ts
const { data, error } = await authClient.organization.checkSlug({
    slug: "my-org", // required, 要检查的组织短名称。
});
```

### Server Side

```ts
const data = await auth.api.checkOrganizationSlug({
    body: {
        slug: "my-org", // required, 要检查的组织短名称。
    },
});
```

### Type Definition

```ts
type checkOrganizationSlug = {
    /**
     * 要检查的组织短名称。  
     */
    slug: string = "my-org"
}
```

### 组织钩子 [#组织钩子]

您可以使用钩子来自定义组织操作，钩子会在各种组织相关活动的前后运行。Better Auth 提供了两种配置钩子的方式：

1. **旧版 organizationCreation 钩子**（已弃用，改用 `organizationHooks`）
2. **现代的 organizationHooks**（推荐）- 提供对所有组织活动的全面控制

#### 组织创建与管理钩子 [#组织创建与管理钩子]

控制组织生命周期操作：

```ts title="auth.ts"
import { betterAuth } from "better-auth";
import { organization } from "better-auth/plugins";

export const auth = betterAuth({
  plugins: [
    organization({
      organizationHooks: {
        // 组织创建前钩子
        beforeCreateOrganization: async ({ organization, user }) => {
          // 在创建组织前运行自定义逻辑
          // 可选地修改组织数据
          return {
            data: {
              ...organization,
              metadata: {
                customField: "value",
              },
            },
          };
        },

        afterCreateOrganization: async ({ organization, member, user }) => {
          // 创建组织后运行自定义逻辑
          // 例如，创建默认资源，发送通知
          await setupDefaultResources(organization.id);
        },

        // 组织更新前钩子
        beforeUpdateOrganization: async ({ organization, user, member }) => {
          // 验证更新，应用业务规则
          return {
            data: {
              ...organization,
              name: organization.name?.toLowerCase(),
            },
          };
        },

        afterUpdateOrganization: async ({ organization, user, member }) => {
          // 将更改同步到外部系统
          await syncOrganizationToExternalSystems(organization);
        },
      },
    }),
  ],
});
```

<Callout type="info">
  旧版 `organizationCreation` 钩子仍受支持，但已弃用。
  新项目请使用 `organizationHooks.beforeCreateOrganization` 和
  `organizationHooks.afterCreateOrganization`。
</Callout>

#### 成员钩子 [#成员钩子]

控制组织内成员操作：

```ts title="auth.ts"
import { betterAuth } from "better-auth";
import { organization } from "better-auth/plugins";

export const auth = betterAuth({
  plugins: [
    organization({
      organizationHooks: {
        // 添加成员前
        beforeAddMember: async ({ member, user, organization }) => {
          // 自定义验证或修改
          console.log(`Adding ${user.email} to ${organization.name}`);

          // 可选地修改成员数据
          return {
            data: {
              ...member,
              role: "custom-role", // 覆盖角色
            },
          };
        },

        // 添加成员后
        afterAddMember: async ({ member, user, organization }) => {
          // 发送欢迎邮件，创建默认资源等
          await sendWelcomeEmail(user.email, organization.name);
        },

        // 移除成员前
        beforeRemoveMember: async ({ member, user, organization }) => {
          // 清理用户资源，发送通知等
          await cleanupUserResources(user.id, organization.id);
        },

        // 移除成员后
        afterRemoveMember: async ({ member, user, organization }) => {
          await logMemberRemoval(user.id, organization.id);
        },

        // 更新成员角色前
        beforeUpdateMemberRole: async ({
          member,
          newRole,
          user,
          organization,
        }) => {
          // 验证角色变更权限
          if (newRole === "owner" && !hasOwnerUpgradePermission(user)) {
            throw new Error("Cannot upgrade to owner role");
          }

          // 可选地修改角色
          return {
            data: {
              role: newRole,
            },
          };
        },

        // 更新成员角色后
        afterUpdateMemberRole: async ({
          member,
          previousRole,
          user,
          organization,
        }) => {
          await logRoleChange(user.id, previousRole, member.role);
        },
      },
    }),
  ],
});
```

#### 邀请钩子 [#邀请钩子]

控制邀请流程：

```ts title="auth.ts"
import { betterAuth } from "better-auth";
import { organization } from "better-auth/plugins";

export const auth = betterAuth({
  plugins: [
    organization({
      organizationHooks: {
        // 创建邀请前
        beforeCreateInvitation: async ({
          invitation,
          inviter,
          organization,
        }) => {
          // 自定义验证或过期逻辑
          const customExpiration = new Date(
            Date.now() + 1000 * 60 * 60 * 24 * 7
          ); // 7 天

          return {
            data: {
              ...invitation,
              expiresAt: customExpiration,
            },
          };
        },

        // 创建邀请后
        afterCreateInvitation: async ({
          invitation,
          inviter,
          organization,
        }) => {
          // 发送自定义邀请邮件，统计指标等
          await sendCustomInvitationEmail(invitation, organization);
        },

        // 接受邀请前
        beforeAcceptInvitation: async ({ invitation, user, organization }) => {
          // 接受前额外验证
          await validateUserEligibility(user, organization);
        },

        // 接受邀请后
        afterAcceptInvitation: async ({
          invitation,
          member,
          user,
          organization,
        }) => {
          // 设置用户账户，分配默认资源
          await setupNewMemberResources(user, organization);
        },

        // 拒绝邀请前后
        beforeRejectInvitation: async ({ invitation, user, organization }) => {
          // 记录拒绝原因，通知邀请者等
        },

        afterRejectInvitation: async ({ invitation, user, organization }) => {
          await notifyInviterOfRejection(invitation.inviterId, user.email);
        },

        // 取消邀请前后
        beforeCancelInvitation: async ({
          invitation,
          cancelledBy,
          organization,
        }) => {
          // 验证取消权限
        },

        afterCancelInvitation: async ({
          invitation,
          cancelledBy,
          organization,
        }) => {
          await logInvitationCancellation(invitation.id, cancelledBy.id);
        },
      },
    }),
  ],
});
```

#### 团队钩子 [#团队钩子]

控制团队操作（启用团队时生效）：

```ts title="auth.ts"
import { betterAuth } from "better-auth";
import { organization } from "better-auth/plugins";

export const auth = betterAuth({
  plugins: [
    organization({
      teams: { enabled: true },
      organizationHooks: {
        // 创建团队前
        beforeCreateTeam: async ({ team, user, organization }) => {
          // 验证团队名称，应用命名规范
          return {
            data: {
              ...team,
              name: team.name.toLowerCase().replace(/\s+/g, "-"),
            },
          };
        },

        // 创建团队后
        afterCreateTeam: async ({ team, user, organization }) => {
          // 创建默认团队资源、频道等
          await createDefaultTeamResources(team.id);
        },

        // 更新团队前
        beforeUpdateTeam: async ({ team, updates, user, organization }) => {
          // 验证更新，应用业务规则
          return {
            data: {
              ...updates,
              name: updates.name?.toLowerCase(),
            },
          };
        },

        // 更新团队后
        afterUpdateTeam: async ({ team, user, organization }) => {
          await syncTeamChangesToExternalSystems(team);
        },

        // 删除团队前
        beforeDeleteTeam: async ({ team, user, organization }) => {
          // 备份团队数据，通知成员
          await backupTeamData(team.id);
        },

        // 删除团队后
        afterDeleteTeam: async ({ team, user, organization }) => {
          await cleanupTeamResources(team.id);
        },

        // 团队成员操作
        beforeAddTeamMember: async ({
          teamMember,
          team,
          user,
          organization,
        }) => {
          // 验证团队成员限制，权限
          const memberCount = await getTeamMemberCount(team.id);
          if (memberCount >= 10) {
            throw new Error("Team is full");
          }
        },

        afterAddTeamMember: async ({
          teamMember,
          team,
          user,
          organization,
        }) => {
          await grantTeamAccess(user.id, team.id);
        },

        beforeRemoveTeamMember: async ({
          teamMember,
          team,
          user,
          organization,
        }) => {
          // 备份用户的团队专属数据
          await backupTeamMemberData(user.id, team.id);
        },

        afterRemoveTeamMember: async ({
          teamMember,
          team,
          user,
          organization,
        }) => {
          await revokeTeamAccess(user.id, team.id);
        },
      },
    }),
  ],
});
```

#### 钩子错误处理 [#钩子错误处理]

所有钩子都支持错误处理。在 `before` 钩子中抛出错误将阻止操作执行：

```ts title="auth.ts"
import { betterAuth } from "better-auth";
import { organization } from "better-auth/plugins";
import { APIError } from "better-auth/api";

export const auth = betterAuth({
  plugins: [
    organization({
      organizationHooks: {
        beforeAddMember: async ({ member, user, organization }) => {
          // 检查用户是否存在未处理违规
          const violations = await checkUserViolations(user.id);
          if (violations.length > 0) {
            throw new APIError("BAD_REQUEST", {
              message:
                "用户有待处理的违规，无法加入组织",
            });
          }
        },

        beforeCreateTeam: async ({ team, user, organization }) => {
          // 验证团队名称唯一性
          const existingTeam = await findTeamByName(team.name, organization.id);
          if (existingTeam) {
            throw new APIError("BAD_REQUEST", {
              message: "此组织中已存在相同的团队名称",
            });
          }
        },
      },
    }),
  ],
});
```

### 列出用户所在组织 [#列出用户所在组织]

要列出用户所在的所有组织，可以使用 `useListOrganizations` 钩子。它可以响应式地获取用户所属组织列表。

<Tabs items="[&#x22;React&#x22;, &#x22;Vue&#x22;, &#x22;Svelte&#x22;]" default="React">
  <Tab value="React">
    ```tsx title="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>)
    }
    ```
  </Tab>

  <Tab value="Svelte">
    ```svelte title="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?.length}
      <p>未找到组织。</p>
    {:else}
      <ul>
        {#each $organizations.data as organization}
          <li>{organization.name}</li>
        {/each}
      </ul>
    {/if}
    ```
  </Tab>

  <Tab value="Vue">
    ```vue title="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>
    ```
  </Tab>
</Tabs>

或者，如果不想使用钩子，也可以调用 `organization.list`。

**Endpoint:** `GET /organization/list`

### Client Side

```ts
const { data, error } = await authClient.organization.list();
```

### Server Side

```ts
const data = await auth.api.listOrganizations({
    // This endpoint requires session cookies.
    headers: await headers(),
});
```

### Type Definition

```ts
type listOrganizations = {
}
```

### 活跃组织 [#活跃组织]

活跃组织是用户当前工作的工作区。默认情况下，用户登录时活跃组织设置为 `null`。您可以为用户会话设置活跃组织。

<Callout type="info">
  并非所有情况下都需要在会话中持久化活跃组织。
  您可以仅在客户端管理活跃组织。例如，
  多个标签页可以有不同的活跃组织。
</Callout>

#### 设置活跃组织 [#设置活跃组织]

您可以调用 `organization.setActive` 函数设置活跃组织。它会将活跃组织设置到用户会话中。

<Callout>
  在某些应用中，您可能希望能取消设置活跃组织。
  这时可以调用此接口，将 `organizationId` 设置为 `null`。
</Callout>

**Endpoint:** `POST /organization/set-active`

### Client Side

```ts
const { data, error } = await authClient.organization.setActive({
    organizationId: "org-id", // 要设为活跃的组织 ID。也可以为 null，以取消设置活跃组织。
    organizationSlug: "org-slug", // 要设为活跃的组织短名称。如果未提供 organizationId，则也可以为 null，以取消设置活跃组织。
});
```

### Server Side

```ts
const data = await auth.api.setActiveOrganization({
    body: {
        organizationId: "org-id", // 要设为活跃的组织 ID。也可以为 null，以取消设置活跃组织。
        organizationSlug: "org-slug", // 要设为活跃的组织短名称。如果未提供 organizationId，则也可以为 null，以取消设置活跃组织。
    },
    // This endpoint requires session cookies.
    headers: await headers(),
});
```

### Type Definition

```ts
type setActiveOrganization = {
    /**
     * 要设为活跃的组织 ID。也可以为 null，以取消设置活跃组织。  
     */
    organizationId?: string | null = "org-id"
    /**
     * 要设为活跃的组织短名称。如果未提供 organizationId，则也可以为 null，以取消设置活跃组织。  
     */
    organizationSlug?: string = "org-slug"
}
```

要在会话创建时自动设置活跃组织，可以使用 [数据库钩子](/docs/concepts/database#数据库钩子)。您需要实现逻辑，以确定初始活跃组织。

```ts title="auth.ts"
import { betterAuth } from "better-auth";

export const auth = betterAuth({
  databaseHooks: {
    session: {
      create: {
        before: async (session) => {
          // 自定义设置初始活跃组织逻辑
          const organization = await getInitialOrganization(session.userId);
          return {
            data: {
              ...session,
              activeOrganizationId: organization?.id,
            },
          };
        },
      },
    },
  },
});
```

#### 使用活跃组织 [#使用活跃组织]

要获取用户的活跃组织，可以调用 `useActiveOrganization` 钩子。该钩子返回用户的活跃组织，并会在其变化时重新评估。

<Tabs items="['React', 'Vue', 'Svelte']">
  <Tab value="React">
    ```tsx title="client.tsx"
    import { authClient } from "@/lib/auth-client"

    function App(){
        const { data: activeOrganization } = authClient.useActiveOrganization()
        return (
            <div>
                {activeOrganization ? <p>{activeOrganization.name}</p> : null}
            </div>
        )
    }
    ```
  </Tab>

  <Tab value="Svelte">
    ```tsx title="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}
    ```
  </Tab>

  <Tab value="Vue">
    ```vue title="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>
    ```
  </Tab>
</Tabs>

### 获取组织 [#获取组织]

要获取不包含成员或邀请的组织元数据，请使用 `getOrganization`。
默认情况下，如果不传递任何属性，它将使用活跃组织。

当您只需要 `id`、`name`、`slug`、`logo` 和 `metadata` 等字段时，优先使用此方法，而不是 `getFullOrganization`。

**Endpoint:** `GET /organization/get-organization`

### Client Side

```ts
const { data, error } = await authClient.organization.getOrganization({
    query: {
        organizationId: "org-id", // 要获取的组织 ID。默认情况下，将使用活跃组织。
        organizationSlug: "org-slug", // 要获取的组织短名称。
    },
});
```

### Server Side

```ts
const data = await auth.api.getOrganization({
    query: {
        organizationId: "org-id", // 要获取的组织 ID。默认情况下，将使用活跃组织。
        organizationSlug: "org-slug", // 要获取的组织短名称。
    },
    // This endpoint requires session cookies.
    headers: await headers(),
});
```

### Type Definition

```ts
type getOrganization = {
    /**
     * 要获取的组织 ID。默认情况下，将使用活跃组织。  
     */
    organizationId?: string = "org-id"
    /**
     * 要获取的组织短名称。  
     */
    organizationSlug?: string = "org-slug"
}
```

### 获取完整组织 [#获取完整组织]

要获取组织的完整详情，可以使用 `getFullOrganization` 函数。默认情况下，如果不传任何属性，将使用活跃组织。

**Endpoint:** `GET /organization/get-full-organization`

### Client Side

```ts
const { data, error } = await authClient.organization.getFullOrganization({
    query: {
        organizationId: "org-id", // 要获取的组织 ID。默认情况下，它将使用活跃组织。
        organizationSlug: "org-slug", // 要获取的组织短名称。
        membersLimit: 100, // 要获取的成员数量上限。默认使用 membershipLimit 选项，其默认值为 100。
    },
});
```

### Server Side

```ts
const data = await auth.api.getFullOrganization({
    query: {
        organizationId: "org-id", // 要获取的组织 ID。默认情况下，它将使用活跃组织。
        organizationSlug: "org-slug", // 要获取的组织短名称。
        membersLimit: 100, // 要获取的成员数量上限。默认使用 membershipLimit 选项，其默认值为 100。
    },
    // This endpoint requires session cookies.
    headers: await headers(),
});
```

### Type Definition

```ts
type getFullOrganization = {
    /**
     * 要获取的组织 ID。默认情况下，它将使用活跃组织。  
     */
    organizationId?: string = "org-id"
    /**
     * 要获取的组织短名称。  
     */
    organizationSlug?: string = "org-slug"
    /**
     * 要获取的成员数量上限。默认使用 membershipLimit 选项，其默认值为 100。
     */
    membersLimit?: number = 100
}
```

### 更新组织 [#更新组织]

要更新组织信息，可以使用 `organization.update`。

**Endpoint:** `POST /organization/update`

### Client Side

```ts
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", // 要更新的组织 ID。
});
```

### Server Side

```ts
const data = await auth.api.updateOrganization({
    body: {
        data: { // required, 要更新组织的部分数据列表。
            name: "updated-name", // 组织名称。
            slug: "updated-slug", // 组织短名称。
            logo: "new-logo.url", // 组织徽标。
            metadata: { customerId: "test" }, // 组织的元数据。
        },
        organizationId: "org-id", // 要更新的组织 ID。
    },
    // This endpoint requires session cookies.
    headers: await headers(),
});
```

### Type Definition

```ts
type updateOrganization = {
    /**
     * 要更新组织的部分数据列表。 
     */
    data: {
        /**
         * 组织名称。 
         */
        name?: string = "updated-name"
        /**
         * 组织短名称。 
         */
        slug?: string = "updated-slug"
        /**
         * 组织徽标。
         */
        logo?: string | null = "new-logo.url"
        /**
         * 组织的元数据。 
         */
        metadata?: Record<string, any> | null = { customerId: "test" }
    }
    /**
     * 要更新的组织 ID。
     */
    organizationId?: string = "org-id"
}
```

### 删除组织 [#删除组织]

要删除用户拥有的组织，可以使用 `organization.delete`。

**Endpoint:** `POST /organization/delete`

### Client Side

```ts
const { data, error } = await authClient.organization.delete({
    organizationId: "org-id", // required, 要删除的组织 ID。
});
```

### Server Side

```ts
const data = await auth.api.deleteOrganization({
    body: {
        organizationId: "org-id", // required, 要删除的组织 ID。
    },
    // This endpoint requires session cookies.
    headers: await headers(),
});
```

### Type Definition

```ts
type deleteOrganization = {
    /*
    * 要删除的组织 ID。
    */
    organizationId: string = "org-id"
}
```

如果用户在指定组织中拥有必要权限（默认角色为所有者），则会删除所有成员、邀请和组织信息。

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

```ts title="auth.ts"
import { betterAuth } from "better-auth";
import { organization } from "better-auth/plugins";

const auth = betterAuth({
  plugins: [
    organization({
      disableOrganizationDeletion: true, // 完全禁用删除功能
      organizationHooks: {
        beforeDeleteOrganization: async (data, ctx) => {
          // 在删除组织之前运行的回调
          // `ctx` 是端点上下文（例如 `ctx?.request`）
        },
        afterDeleteOrganization: async (data, ctx) => {
          // 在删除组织之后运行的回调
        },
      },
    }),
  ],
});
```

## 邀请 [#邀请]

要添加成员到组织，首先需要向用户发送邀请。用户会收到包含邀请链接的邮件或短信。用户接受邀请后，将被添加到组织中。

### 设置邀请邮件 [#设置邀请邮件]

要实现成员邀请功能，首先需要为 `better-auth` 实例配置 `sendInvitationEmail`。此函数负责向用户发送邀请邮件。

您需要构造并发送邀请链接给用户，该链接应包含邀请 ID，用户点击时用于调用 `acceptInvitation`。

```ts title="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` 函数。此函数接受如下对象：

**Endpoint:** `POST /organization/invite-member`

### Client Side

```ts
const { data, error } = await authClient.organization.inviteMember({
    email: "example@gmail.com", // required, 要邀请的用户邮箱地址。
    role: "member", // required, 要分配给用户的角色。可以是 `admin`、`member`、`owner`
    organizationId: "org-id", // 要邀请用户加入的组织 ID。默认使用当前活跃组织。
    resend: true, // 如果用户已被邀请，是否重新发送邀请邮件。
    teamId: "team-id", // 要邀请用户加入的团队 ID。
});
```

### Server Side

```ts
const data = await auth.api.createInvitation({
    body: {
        email: "example@gmail.com", // required, 要邀请的用户邮箱地址。
        role: "member", // required, 要分配给用户的角色。可以是 `admin`、`member`、`owner`
        organizationId: "org-id", // 要邀请用户加入的组织 ID。默认使用当前活跃组织。
        resend: true, // 如果用户已被邀请，是否重新发送邀请邮件。
        teamId: "team-id", // 要邀请用户加入的团队 ID。
    },
    // This endpoint requires session cookies.
    headers: await headers(),
});
```

### Type Definition

```ts
type createInvitation = {
    /**
     * 要邀请的用户邮箱地址。  
     */
    email: string = "example@gmail.com"
    /**
     * 要分配给用户的角色。可以是 `admin`、`member`、`owner`
     */
    role: string | string[] = "member"
    /**
     * 要邀请用户加入的组织 ID。默认使用当前活跃组织。  
     */
    organizationId?: string = "org-id"
    /**
     * 如果用户已被邀请，是否重新发送邀请邮件。  
     */
    resend?: boolean = true
    /**
     * 要邀请用户加入的团队 ID。  
     */
    teamId?: string = "team-id"
}
```

<Callout>
  * 如果用户已经是该组织成员，邀请将被取消。
  * 如果用户已经被邀请到该组织，除非将 `resend` 设为 `true`，否则不会再次发送邀请。
  * 如果将 `cancelPendingInvitationsOnReInvite` 设为 `true`，当用户已被邀请到组织且发送新邀请时，之前的邀请将被取消。
</Callout>

### 接受邀请 [#接受邀请]

用户收到邀请邮件后，可点击邀请链接接受邀请。邀请链接应包含邀请 ID，接受时用于调用对应接口。

请确保用户登录后调用 `acceptInvitation`。

**Endpoint:** `POST /organization/accept-invitation`

### Client Side

```ts
const { data, error } = await authClient.organization.acceptInvitation({
    invitationId: "invitation-id", // required, 要接受的邀请 ID。
});
```

### Server Side

```ts
const data = await auth.api.acceptInvitation({
    body: {
        invitationId: "invitation-id", // required, 要接受的邀请 ID。
    },
    // This endpoint requires session cookies.
    headers: await headers(),
});
```

### Type Definition

```ts
type acceptInvitation = {
    /**
     * 要接受的邀请 ID。  
     */
    invitationId: string = "invitation-id"
}
```

#### 邮箱验证要求 [#邮箱验证要求]

默认情况下，接受邀请需要使用邮件链接中的邀请 ID，并且当前已登录会话的邮箱必须与邀请邮箱匹配。当 Better Auth 使用内置的不可预测邀请 ID 时，包括默认生成器或 `advanced.database.generateId: "uuid"`，这对于正常的邮件邀请流程已经足够。如果邀请 ID 是外部可控或可预测的，例如 `advanced.database.generateId: "serial"` / `false` 或自定义 ID 生成方式，则 Better Auth 还会要求进行邮箱验证，除非您显式将 `requireEmailVerificationOnInvitation` 设为 `false`。

建议将 `requireEmailVerificationOnInvitation` 设为 `true`，以采用更严格的安全策略。当邀请 ID 可能会被邀请用户邮箱之外的人看到、当应用向成员展示组织邀请列表、当使用自定义邀请投递方式，或允许未验证邮箱/密码会话且组织成员资格较敏感时，尤其建议这样做。在登录前要求邮箱验证，可以在流程更早阶段提供相同的所有权证明。

```ts title="auth.ts"
import { betterAuth } from "better-auth";
import { organization } from "better-auth/plugins";

export const auth = betterAuth({
  plugins: [
    organization({
      requireEmailVerificationOnInvitation: true, // [!code highlight]
      async sendInvitationEmail(data) {
        // 邮件发送逻辑
      },
    }),
  ],
});
```

### 取消邀请 [#取消邀请]

若发出邀请后需要取消，可以调用此方法。

如果您想了解用户如何拒绝邀请，可以查看 [拒绝邀请部分](#reject-invitation)。

**Endpoint:** `POST /organization/cancel-invitation`

### Client Side

```ts
await authClient.organization.cancelInvitation({
    invitationId: "invitation-id", // required, 要取消的邀请 ID。
});
```

### Server Side

```ts
await auth.api.cancelInvitation({
    body: {
        invitationId: "invitation-id", // required, 要取消的邀请 ID。
    },
    // This endpoint requires session cookies.
    headers: await headers(),
});
```

### Type Definition

```ts
type cancelInvitation = {
    /**
     * 要取消的邀请 ID。  
     */
    invitationId: string = "invitation-id"
}
```

### 拒绝邀请 [#拒绝邀请]

用户收到邀请但想拒绝，可调用此方法。

**Endpoint:** `POST /organization/reject-invitation`

### Client Side

```ts
await authClient.organization.rejectInvitation({
    invitationId: "invitation-id", // required, 要拒绝的邀请 ID。
});
```

### Server Side

```ts
await auth.api.rejectInvitation({
    body: {
        invitationId: "invitation-id", // required, 要拒绝的邀请 ID。
    },
    // This endpoint requires session cookies.
    headers: await headers(),
});
```

### Type Definition

```ts
type rejectInvitation = {
    /**
     * 要拒绝的邀请 ID。  
     */
    invitationId: string = "invitation-id"
}
```

<Callout type="info">
  拒绝邀请遵循与按 ID 接受邀请相同的邮箱验证策略。
</Callout>

### 获取邀请 [#获取邀请]

您可以使用客户端的 `organization.getInvitation` 获取邀请信息。需提供邀请 ID。

**Endpoint:** `GET /organization/get-invitation`

### Client Side

```ts
const { data, error } = await authClient.organization.getInvitation({
    query: {
        id: "invitation-id", // required, 要获取的邀请 ID。
    },
});
```

### Server Side

```ts
const data = await auth.api.getInvitation({
    query: {
        id: "invitation-id", // required, 要获取的邀请 ID。
    },
    // This endpoint requires session cookies.
    headers: await headers(),
});
```

### Type Definition

```ts
type getInvitation = {
    /**
     * 要获取的邀请 ID。  
     */
    id: string = "invitation-id"
}
```

<Callout type="info">
  通过 ID 获取邀请遵循与按 ID 接受邀请相同的邮箱验证策略。
</Callout>

### 列出邀请 [#列出邀请]

要列出特定组织的所有邀请，可使用客户端的 `listInvitations`。

**Endpoint:** `GET /organization/list-invitations`

### Client Side

```ts
const { data, error } = await authClient.organization.listInvitations({
    query: {
        organizationId: "organization-id", // 用于列出邀请的可选组织 ID。如果未提供，将默认为用户的当前活跃组织。
    },
});
```

### Server Side

```ts
const data = await auth.api.listInvitations({
    query: {
        organizationId: "organization-id", // 用于列出邀请的可选组织 ID。如果未提供，将默认为用户的当前活跃组织。
    },
    // This endpoint requires session cookies.
    headers: await headers(),
});
```

### Type Definition

```ts
type listInvitations = {
    /**
     * 用于列出邀请的可选组织 ID。如果未提供，将默认为用户的当前活跃组织。 
     */
    organizationId?: string = "organization-id"
}
```

响应中包含邀请 ID。请将这些 ID 视为具有操作能力的邀请链接。如果能够列出组织邀请的用户不应使用这些 ID 在未验证的收件人会话中执行操作，请启用 `requireEmailVerificationOnInvitation`，或在应用层为该端点添加权限检查。

### 列出用户邀请 [#列出用户邀请]

要列出给特定用户的所有邀请，可使用客户端的 `listUserInvitations`。

```ts
import { authClient } from "@/lib/auth-client"

const invitations = await authClient.organization.listUserInvitations();
```

客户端侧的 `listUserInvitations` 调用要求会话用户的邮箱已验证。此端点会从会话邮箱中枚举待处理的邀请 ID，因此仅靠邮箱字符串匹配不足以证明所有权。

在服务端，您可以通过查询参数传入用户的邮箱地址。

```ts title="list-user-invitations.ts"
const invitations = await auth.api.listUserInvitations({
  query: {
    email: "user@example.com",
  },
});
```

<Callout type="warn">
  查询参数 `email` 仅在服务器端可用，用于查询指定用户的邀请。
</Callout>

## 成员 [#成员]

### 列出成员 [#列出成员]

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

**Endpoint:** `GET /organization/list-members`

### Client Side

```ts
const { data, error } = await authClient.organization.listMembers({
    query: {
        organizationId: "organization-id", // 用于列出成员的可选组织 ID。如果未提供，将默认为用户的当前活跃组织。
        limit: 100, // 要返回的成员数量上限。
        offset: 0, // 起始偏移量。
        sortBy: "createdAt", // 要排序的字段。
        sortDirection: "desc", // 排序方向。
        filterField: "createdAt", // 要筛选的字段。
        filterOperator: "eq", // 要筛选所用的操作符。
        filterValue: "value", // 要筛选的值。
    },
});
```

### Server Side

```ts
const data = await auth.api.listMembers({
    query: {
        organizationId: "organization-id", // 用于列出成员的可选组织 ID。如果未提供，将默认为用户的当前活跃组织。
        limit: 100, // 要返回的成员数量上限。
        offset: 0, // 起始偏移量。
        sortBy: "createdAt", // 要排序的字段。
        sortDirection: "desc", // 排序方向。
        filterField: "createdAt", // 要筛选的字段。
        filterOperator: "eq", // 要筛选所用的操作符。
        filterValue: "value", // 要筛选的值。
    },
    // This endpoint requires session cookies.
    headers: await headers(),
});
```

### Type Definition

```ts
type listMembers = {
    /**
     * 用于列出成员的可选组织 ID。如果未提供，将默认为用户的当前活跃组织。
     */
    organizationId?: string = "organization-id"
    /**
     * 要返回的成员数量上限。
     */
    limit?: number = 100
    /**
     * 起始偏移量。
     */
    offset?: number = 0
    /**
     * 要排序的字段。
     */
    sortBy?: string = "createdAt"
    /**
     * 排序方向。
     */
    sortDirection?: "asc" | "desc" = "desc"
    /**
     * 要筛选的字段。
     */
    filterField?: string = "createdAt"
    /**
     * 要筛选所用的操作符。
     */
    filterOperator?: "eq" | "ne" | "lt" | "lte" | "gt" | "gte" | "in" | "not_in" | "contains" | "starts_with" | "ends_with" = "eq"
    /**
     * 要筛选的值。
     */
    filterValue?: string | number | boolean | string[] | number[] = "value"
}
```

### 移除成员 [#移除成员]

您可以调用 `organization.removeMember` 来移除成员。

**Endpoint:** `POST /organization/remove-member`

### Client Side

```ts
const { data, error } = await authClient.organization.removeMember({
    memberIdOrEmail: "user@example.com", // required, 要移除的成员的 ID 或邮箱。
    organizationId: "org-id", // 要从中移除成员的组织 ID。如果未提供，将使用当前活跃组织。
});
```

### Server Side

```ts
const data = await auth.api.removeMember({
    body: {
        memberIdOrEmail: "user@example.com", // required, 要移除的成员的 ID 或邮箱。
        organizationId: "org-id", // 要从中移除成员的组织 ID。如果未提供，将使用当前活跃组织。
    },
    // This endpoint requires session cookies.
    headers: await headers(),
});
```

### Type Definition

```ts
type removeMember = {
    /**
     * 要移除的成员的 ID 或邮箱。 
     */
    memberIdOrEmail: string = "user@example.com"
    /**
     * 要从中移除成员的组织 ID。如果未提供，将使用当前活跃组织。 
     */
    organizationId?: string = "org-id"
}
```

### 更新成员角色 [#更新成员角色]

您可以使用 `organization.updateMemberRole` 来更新组织内成员的角色。若当前用户有权限，角色将被更新。

**Endpoint:** `POST /organization/update-member-role`

### Client Side

```ts
await authClient.organization.updateMemberRole({
    role: ["admin", "sale"], // required, 要应用的新角色。可以是表示角色的字符串或字符串数组。
    memberId: "member-id", // required, 要更新角色的成员 ID。
    organizationId: "organization-id", // 可选的组织 ID，成员所属的组织。若未提供，则必须提供会话头以获取当前活跃组织。
});
```

### Server Side

```ts
await auth.api.updateMemberRole({
    body: {
        role: ["admin", "sale"], // required, 要应用的新角色。可以是表示角色的字符串或字符串数组。
        memberId: "member-id", // required, 要更新角色的成员 ID。
        organizationId: "organization-id", // 可选的组织 ID，成员所属的组织。若未提供，则必须提供会话头以获取当前活跃组织。
    },
    // This endpoint requires session cookies.
    headers: await headers(),
});
```

### Type Definition

```ts
type updateMemberRole = {
    /**
     * 要应用的新角色。可以是表示角色的字符串或字符串数组。 
     */
    role: string | string[] = ["admin", "sale"]
    /**
     * 要更新角色的成员 ID。 
     */
    memberId: string = "member-id"
    /**
     * 可选的组织 ID，成员所属的组织。若未提供，则必须提供会话头以获取当前活跃组织。 
     */
    organizationId?: string = "organization-id"
}
```

### 获取当前活跃成员 [#获取当前活跃成员]

获取当前活跃组织的成员详细信息，调用 `organization.getActiveMember`。

**Endpoint:** `GET /organization/get-active-member`

### Client Side

```ts
const { data: member, error } = await authClient.organization.getActiveMember();
```

### Server Side

```ts
const member = await auth.api.getActiveMember({
    // This endpoint requires session cookies.
    headers: await headers(),
});
```

### Type Definition

```ts
type getActiveMember = {
}
```

### 获取当前活跃成员角色 [#获取当前活跃成员角色]

要获取当前活跃组织中该成员的角色，可使用 `organization.getActiveMemberRole` 函数。此函数会返回用户在当前活跃组织中的成员角色。

**Endpoint:** `GET /organization/get-active-member-role`

### Client Side

```ts
const { data: { role }, error } = await authClient.organization.getActiveMemberRole();
```

### Server Side

```ts
const { role } = await auth.api.getActiveMemberRole({
    // This endpoint requires session cookies.
    headers: await headers(),
});
```

### Type Definition

```ts
type getActiveMemberRole = {
}
```

### 添加成员 [#添加成员]

如果想直接添加成员到组织（不发送邀请），可以使用只能在服务器调用的 `addMember` 接口。

**Endpoint:** `POST /organization/add-member`

### Server Side

```ts
const data = await auth.api.addMember({
    body: {
        userId: "user-id", // 表示要添加为成员的用户 ID。如果提供 `null`，则需要提供会话头。
        role: ["admin", "sale"], // required, 要分配给新成员的角色。
        organizationId: "org-id", // 可选的组织 ID。如果未提供，将默认为用户的当前活跃组织。
        teamId: "team-id", // 可选的团队 ID，要将成员添加到该团队。
    },
});
```

### Type Definition

```ts
type addMember = {
    /**
     * 表示要添加为成员的用户 ID。如果提供 `null`，则需要提供会话头。 
     */
    userId?: string | null = "user-id"
    /**
     * 要分配给新成员的角色。 
     */
    role: string | string[] = ["admin", "sale"]
    /**
     * 可选的组织 ID。如果未提供，将默认为用户的当前活跃组织。 
     */
    organizationId?: string = "org-id"
    /**
     * 可选的团队 ID，要将成员添加到该团队。 
     */
    teamId?: string = "team-id"
}
```

### 退出组织 [#退出组织]

调用 `organization.leave` 函数，让当前用户退出组织。

**Endpoint:** `POST /organization/leave`

### Client Side

```ts
await authClient.organization.leave({
    organizationId: "organization-id", // required, 成员要退出的组织 ID。
});
```

### Server Side

```ts
await auth.api.leaveOrganization({
    body: {
        organizationId: "organization-id", // required, 成员要退出的组织 ID。
    },
    // This endpoint requires session cookies.
    headers: await headers(),
});
```

### Type Definition

```ts
type leaveOrganization = {
    /**
     * 成员要退出的组织 ID。 
     */
    organizationId: string = "organization-id"
}
```

## 访问控制 [#访问控制]

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

### 角色 [#角色]

默认情况下，组织中有三种角色：

`owner`（所有者）：默认创建组织的用户，拥有组织的完全控制权，并可执行任何操作。

`admin`（管理员）：拥有除删除组织和更改所有者外的完全控制权。

`member`（成员）：权限受限，仅能读取组织数据，无权限创建、更新或删除资源。

<Callout>
  用户可拥有多个角色。多个角色以逗号（","）分隔的字符串存储。
</Callout>

### 权限 [#权限]

默认定义了三个资源，每个资源具有两到三个操作。

**organization**：

`update` `delete`

**member**：

`create` `update` `delete`

**invitation**：

`create` `cancel`

所有者拥有所有资源和操作的完整控制。管理员拥有除删除组织和更改所有者权之外的完整控制。成员仅有读取权限。

### 自定义权限 [#自定义权限]

插件提供了简单的方式，为每个角色定义自定义权限。

<Steps>
  <Step>
    #### 创建访问控制 [#创建访问控制]

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

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

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

    const ac = createAccessControl(statement); // [!code highlight]
    ```

    <Callout type="warning">
      为减小包体积，请从 `better-auth/plugins/access` 导入，而非 `better-auth/plugins`。
    </Callout>
  </Step>

  <Step>
    #### 创建角色 [#创建角色]

    创建访问控制后，可以根据权限声明创建角色。

    ```ts title="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({ // [!code highlight]
        project: ["create"], // [!code highlight]
    }); // [!code highlight]

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

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

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

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

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

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

    const ac = createAccessControl(statement);

    const admin = ac.newRole({
        project: ["create", "update"],
        ...adminAc.statements, // [!code highlight]
    });
    ```
  </Step>

  <Step>
    #### 将角色传递给插件 [#将角色传递给插件]

    一旦创建好角色，就可以在客户端和服务器端把它们传递给组织插件。

    ```ts title="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
                }
            }),
        ],
    });
    ```

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

    ```ts title="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
                }
            })
      ]
    })
    ```
  </Step>
</Steps>

### 访问控制使用 [#访问控制使用]

**权限检查**：

可调用 `api` 提供的 `hasPermission` 方法检测用户权限。

```ts title="has-permission.ts"
import { auth } from "@/lib/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`。

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

// 同时检查多个权限
const canCreateProjectAndCreateSale =
  await authClient.organization.hasPermission({
    permissions: {
      project: ["create"],
      sale: ["create"],
    },
  });
```

**检查角色权限**：

定义好角色权限后，客户端可用 `checkRolePermission` 方法同步检查权限，避免每次请求服务器。

```ts title="auth-client.ts"
import { authClient } from "@/lib/auth-client"

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

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

<Callout type="warn">
  该方法不会包含任何动态角色，因其是客户端同步执行。
  如需包含动态角色权限，请使用 [hasPermission](#access-control-usage) API。
</Callout>

***

## 动态访问控制 [#动态访问控制]

动态访问控制允许您在运行时为组织创建角色。通过在数据库表中存储组织关联的角色及权限实现。

### 启用动态访问控制 [#启用动态访问控制]

要启用动态访问控制，请向服务器和客户端插件传入 `dynamicAccessControl` 配置项，设置 `enabled: true`。

确保服务器端的 `ac` 实例已预定义，因其用于推断可用权限。

```ts title="auth.ts"
import { betterAuth } from "better-auth";
import { organization } from "better-auth/plugins";
import { ac } from "@/auth/permissions";

export const auth = betterAuth({
    plugins: [
        organization({ // [!code highlight]
            ac, // 必须定义以支持动态访问控制 // [!code highlight]
            dynamicAccessControl: { // [!code highlight]
              enabled: true, // [!code highlight]
            }, // [!code highlight]
        }) // [!code highlight]
    ]
})
```

```ts title="auth-client.ts"
import { createAuthClient } from "better-auth/client";
import { organizationClient } from "better-auth/client/plugins";

export const authClient = createAuthClient({
    plugins: [
        organizationClient({ // [!code highlight]
            dynamicAccessControl: { // [!code highlight]
              enabled: true, // [!code highlight]
            }, // [!code highlight]
        }) // [!code highlight]
    ]
})
```

<Callout>
  启用后，需要迁移新增数据库中的 `organizationRole` 表。
</Callout>

<Callout type="warn">
  `authClient.organization.checkRolePermission` 函数仍不会包含动态角色，因为它在客户端同步执行。
  请使用 [hasPermission](#access-control-usage) API 以包含动态角色权限检查。
</Callout>

### 创建角色 [#创建角色-1]

运行时为组织创建新角色，可调用 `createRole`。

仅具备 `ac` 资源中 `create` 权限的角色可创建新角色。
默认情况下，只有管理员和所有者拥有该权限。
并且无法添加超出自身权限的权限。

**Endpoint:** `POST /organization/create-role`

### Client Side

```ts
// 要使用自定义资源或权限，
// 请确保它们已在组织配置的 `ac` 实例中定义。
const permission = {
  project: ["create", "update", "delete"]
}
await authClient.organization.createRole({
    role: "my-unique-role", // required, 要创建的角色的唯一名称。
    permission: permission, // 要分配给该角色的权限。
    organizationId: "organization-id", // 将创建该角色的组织 ID。默认为当前活跃组织。
});
```

### Server Side

```ts
// 要使用自定义资源或权限，
// 请确保它们已在组织配置的 `ac` 实例中定义。
const permission = {
  project: ["create", "update", "delete"]
}
await auth.api.createOrgRole({
    body: {
        role: "my-unique-role", // required, 要创建的角色的唯一名称。
        permission: permission, // 要分配给该角色的权限。
        organizationId: "organization-id", // 将创建该角色的组织 ID。默认为当前活跃组织。
    },
    // This endpoint requires session cookies.
    headers: await headers(),
});
```

### Type Definition

```ts
type createOrgRole = {
    /**
     * 要创建的角色的唯一名称。
     */
    role: string = "my-unique-role"
    /**
     * 要分配给该角色的权限。
     */
    permission?: Record<string, string[]> = permission,
    /**
     * 将创建该角色的组织 ID。默认为当前活跃组织。
     */
    organizationId?: string = "organization-id"
}
```

之后可随时调用 [`updateMemberRole`](#update-member-role)，将新角色赋予成员！

### 删除角色 [#删除角色]

删除角色时调用 `deleteRole`，需提供 `roleName` 或 `roleId` 以及 `organizationId`。

**Endpoint:** `POST /organization/delete-role`

### Client Side

```ts
await authClient.organization.deleteRole({
    roleName: "my-role", // 要删除的角色名称。或者，你也可以改为传入 `roleId` 参数。
    roleId: "role-id", // 要删除的角色 ID。或者，你也可以改为传入 `roleName` 参数。
    organizationId: "organization-id", // 将删除该角色的组织 ID。默认为当前活跃组织。
});
```

### Server Side

```ts
await auth.api.deleteOrgRole({
    body: {
        roleName: "my-role", // 要删除的角色名称。或者，你也可以改为传入 `roleId` 参数。
        roleId: "role-id", // 要删除的角色 ID。或者，你也可以改为传入 `roleName` 参数。
        organizationId: "organization-id", // 将删除该角色的组织 ID。默认为当前活跃组织。
    },
    // This endpoint requires session cookies.
    headers: await headers(),
});
```

### Type Definition

```ts
type deleteOrgRole = {
    /**
     * 要删除的角色名称。或者，你也可以改为传入 `roleId` 参数。
     */
    roleName?: string = "my-role"
    /**
     * 要删除的角色 ID。或者，你也可以改为传入 `roleName` 参数。
     */
    roleId?: string = "role-id"
    /**
     * 将删除该角色的组织 ID。默认为当前活跃组织。
     */
    organizationId?: string = "organization-id"
}
```

### 列出角色 [#列出角色]

调用 `listOrgRoles` 列出组织内的所有角色。
该操作要求成员具有 `ac` 资源中的 `read` 权限。

**Endpoint:** `GET /organization/list-roles`

### Client Side

```ts
const { data: roles, error } = await authClient.organization.listRoles({
    query: {
        organizationId: "organization-id", // 要列出的角色所属的组织 ID。默认为用户当前活跃组织。
    },
});
```

### Server Side

```ts
const roles = await auth.api.listOrgRoles({
    query: {
        organizationId: "organization-id", // 要列出的角色所属的组织 ID。默认为用户当前活跃组织。
    },
    // This endpoint requires session cookies.
    headers: await headers(),
});
```

### Type Definition

```ts
type listOrgRoles = {
    /**
     * 要列出的角色所属的组织 ID。默认为用户当前活跃组织。 
     */
    organizationId?: string = "organization-id"
}
```

### 获取指定角色 [#获取指定角色]

**Endpoint:** `GET /organization/get-role`

### Client Side

```ts
const { data: role, error } = await authClient.organization.getRole({
    query: {
        roleName: "my-role", // 要获取的角色名称。或者，你也可以改为传入 `roleId` 参数。
        roleId: "role-id", // 要获取的角色 ID。或者，你也可以改为传入 `roleName` 参数。
        organizationId: "organization-id", // 将检索该角色的组织 ID。默认为当前活跃组织。
    },
});
```

### Server Side

```ts
const role = await auth.api.getOrgRole({
    query: {
        roleName: "my-role", // 要获取的角色名称。或者，你也可以改为传入 `roleId` 参数。
        roleId: "role-id", // 要获取的角色 ID。或者，你也可以改为传入 `roleName` 参数。
        organizationId: "organization-id", // 将检索该角色的组织 ID。默认为当前活跃组织。
    },
    // This endpoint requires session cookies.
    headers: await headers(),
});
```

### Type Definition

```ts
type getOrgRole = {
    /**
     * 要获取的角色名称。或者，你也可以改为传入 `roleId` 参数。
     */
    roleName?: string = "my-role"
    /**
     * 要获取的角色 ID。或者，你也可以改为传入 `roleName` 参数。
     */
    roleId?: string = "role-id"
    /**
     * 将检索该角色的组织 ID。默认为当前活跃组织。
     */
    organizationId?: string = "organization-id"
}
```

### 更新角色 [#更新角色]

**Endpoint:** `POST /organization/update-role`

### Client Side

```ts
const { data: updatedRole, error } = await authClient.organization.updateRole({
    roleName: "my-role", // 要更新的角色名称。或者，你也可以改为传入 `roleId` 参数。
    roleId: "role-id", // 要更新的角色 ID。或者，你也可以改为传入 `roleName` 参数。
    organizationId: "organization-id", // 将更新该角色的组织 ID。默认为当前活跃组织。
    data: { // required, 将被更新的数据
        permission: { project: ["create", "update", "delete"] }, // 可选：更新角色权限。
        roleName: "my-new-role", // 可选：更新角色名称。
    },
});
```

### Server Side

```ts
const updatedRole = await auth.api.updateOrgRole({
    body: {
        roleName: "my-role", // 要更新的角色名称。或者，你也可以改为传入 `roleId` 参数。
        roleId: "role-id", // 要更新的角色 ID。或者，你也可以改为传入 `roleName` 参数。
        organizationId: "organization-id", // 将更新该角色的组织 ID。默认为当前活跃组织。
        data: { // required, 将被更新的数据
            permission: { project: ["create", "update", "delete"] }, // 可选：更新角色权限。
            roleName: "my-new-role", // 可选：更新角色名称。
        },
    },
    // This endpoint requires session cookies.
    headers: await headers(),
});
```

### Type Definition

```ts
type updateOrgRole = {
    /**
     * 要更新的角色名称。或者，你也可以改为传入 `roleId` 参数。
     */
    roleName?: string = "my-role"
    /**
     * 要更新的角色 ID。或者，你也可以改为传入 `roleName` 参数。
     */
    roleId?: string = "role-id"
    /**
     * 将更新该角色的组织 ID。默认为当前活跃组织。
     */
    organizationId?: string = "organization-id"
    /**
     * 将被更新的数据
    */
    data: {
      /**
       * 可选：更新角色权限。
       */
      permission?: Record<string, string[]> = { project: ["create", "update", "delete"] }
      /**
       * 可选：更新角色名称。
       */
      roleName?: string = "my-new-role"
    }
}
```

### 配置选项 [#配置选项]

以下是可传递给 `dynamicAccessControl` 对象的选项列表。

#### `enabled` [#enabled]

启用或禁用动态访问控制，默认禁用。

```ts
organization({
  dynamicAccessControl: {
    enabled: true // [!code highlight]
  }
})
```

#### `maximumRolesPerOrganization` [#maximumrolesperorganization]

限制每个组织可创建的角色数量。

默认不设限制。

```ts
organization({
  dynamicAccessControl: {
    maximumRolesPerOrganization: 10 // [!code highlight]
  }
})
```

也可以传入返回数字的函数。

```ts
organization({
  dynamicAccessControl: {
    maximumRolesPerOrganization: async (organizationId) => { // [!code highlight]
      const organization = await getOrganization(organizationId); // [!code highlight]
      return organization.plan === "pro" ? 100 : 10; // [!code highlight]
    } // [!code highlight]
  }
})
```

### 额外字段 [#额外字段]

要在 `organizationRole` 表中添加额外字段，可传递 `additionalFields` 配置项。

```ts
organization({
  schema: {
    organizationRole: {
      additionalFields: {
        // 角色颜色！
        color: {
          type: "string",
          defaultValue: "#ffffff",
        },
        //... 其他字段
      },
    },
  },
})
```

如果未使用 `inferOrgAdditionalFields` 推断额外字段，可以使用它来推断。

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

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

否则，你可以直接传递 schema 值，就像在服务器端的 org 插件中一样。

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

export const authClient = createAuthClient({
    plugins: [
        organizationClient({
            schema: {
                organizationRole: {
                    additionalFields: {
                        color: {
                            type: "string",
                            defaultValue: "#ffffff",
                        }
                    }
                }
            }
        })
    ]
})
```

***

## 团队 [#团队]

团队允许您在组织内对成员进行分组。团队功能提供了额外的组织结构，可用于更精细地管理权限。

### 启用团队 [#启用团队]

向服务器和客户端插件传递 `teams` 配置项以启用团队：

```ts title="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, // 可选：禁止移除最后一个团队
      },
    }),
  ],
});
```

```ts title="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,
      },
    }),
  ],
});
```

### 团队管理 [#团队管理]

#### 创建团队 [#创建团队]

在组织内创建新团队：

**Endpoint:** `POST /organization/create-team`

### Client Side

```ts
const { data, error } = await authClient.organization.createTeam({
    name: "my-team", // required, 团队名称。
    organizationId: "organization-id", // 将创建该团队的组织 ID。默认为当前活跃组织。
});
```

### Server Side

```ts
const data = await auth.api.createTeam({
    body: {
        name: "my-team", // required, 团队名称。
        organizationId: "organization-id", // 将创建该团队的组织 ID。默认为当前活跃组织。
    },
});
```

### Type Definition

```ts
type createTeam = {
    /**
     * 团队名称。
     */
    name: string = "my-team"
    /**
     * 将创建该团队的组织 ID。默认为当前活跃组织。 
     */
    organizationId?: string = "organization-id"
}
```

#### 列出团队 [#列出团队]

获取组织内的所有团队：

**Endpoint:** `GET /organization/list-teams`

### Client Side

```ts
const { data, error } = await authClient.organization.listTeams({
    query: {
        organizationId: "organization-id", // 要列出的团队所属的组织 ID。默认为用户当前活跃组织。
    },
});
```

### Server Side

```ts
const data = await auth.api.listOrganizationTeams({
    query: {
        organizationId: "organization-id", // 要列出的团队所属的组织 ID。默认为用户当前活跃组织。
    },
    // This endpoint requires session cookies.
    headers: await headers(),
});
```

### Type Definition

```ts
type listOrganizationTeams = {
    /**
     * 要列出的团队所属的组织 ID。默认为用户当前活跃组织。 
     */
    organizationId?: string = "organization-id"
}
```

#### 更新团队 [#更新团队]

更新团队详情：

**Endpoint:** `POST /organization/update-team`

### Client Side

```ts
const { data, error } = await authClient.organization.updateTeam({
    teamId: "team-id", // required, 要更新的团队 ID。
    data: { // required, 包含待更新选项的部分对象。
        name: "My new team name", // 要更新的团队名称。
        organizationId: "My new organization ID for this team", // 该团队所属的组织 ID。
        createdAt: new Date(), // 团队创建时的时间戳。
        updatedAt: new Date(), // 团队上次更新时的时间戳。
    },
});
```

### Server Side

```ts
const data = await auth.api.updateTeam({
    body: {
        teamId: "team-id", // required, 要更新的团队 ID。
        data: { // required, 包含待更新选项的部分对象。
            name: "My new team name", // 要更新的团队名称。
            organizationId: "My new organization ID for this team", // 该团队所属的组织 ID。
            createdAt: new Date(), // 团队创建时的时间戳。
            updatedAt: new Date(), // 团队上次更新时的时间戳。
        },
    },
    // This endpoint requires session cookies.
    headers: await headers(),
});
```

### Type Definition

```ts
type updateTeam = {
    /**
     * 要更新的团队 ID。 
     */
    teamId: string = "team-id"
    /**
     * 包含待更新选项的部分对象。
     */
    data: {
        /**
         * 要更新的团队名称。
         */
        name?: string = "My new team name"
        /**
         * 该团队所属的组织 ID。
         */
        organizationId?: string = "My new organization ID for this team"
        /**
         * 团队创建时的时间戳。
         */
        createdAt?: Date = new Date()
        /**
         * 团队上次更新时的时间戳。
         */
        updatedAt?: Date = new Date()
    }
}
```

#### 移除团队 [#移除团队]

从组织中删除团队：

**Endpoint:** `POST /organization/remove-team`

### Client Side

```ts
const { data, error } = await authClient.organization.removeTeam({
    teamId: "team-id", // required, 要移除的团队 ID。
    organizationId: "organization-id", // 该团队所属的组织 ID。如果未提供，则默认为用户当前活跃组织。
});
```

### Server Side

```ts
const data = await auth.api.removeTeam({
    body: {
        teamId: "team-id", // required, 要移除的团队 ID。
        organizationId: "organization-id", // 该团队所属的组织 ID。如果未提供，则默认为用户当前活跃组织。
    },
});
```

### Type Definition

```ts
type removeTeam = {
    /**
     * 要移除的团队 ID。 
     */
    teamId: string = "team-id"
    /**
     * 该团队所属的组织 ID。如果未提供，则默认为用户当前活跃组织。 
     */
    organizationId?: string = "organization-id"
}
```

#### 设置活跃团队 [#设置活跃团队]

将指定团队设为当前活跃组织的当前活跃团队。如果 `teamId` 为 `null`，则取消当前活跃团队。

**Endpoint:** `POST /organization/set-active-team`

### Client Side

```ts
const { data, error } = await authClient.organization.setActiveTeam({
    teamId: "team-id", // 要设置为当前活跃团队的团队 ID。 该团队必须属于当前活跃组织。
});
```

### Server Side

```ts
const data = await auth.api.setActiveTeam({
    body: {
        teamId: "team-id", // 要设置为当前活跃团队的团队 ID。 该团队必须属于当前活跃组织。
    },
    // This endpoint requires session cookies.
    headers: await headers(),
});
```

### Type Definition

```ts
type setActiveTeam = {
    /**
     * 要设置为当前活跃团队的团队 ID。
     * 该团队必须属于当前活跃组织。
     */
    teamId?: string | null = "team-id"
}
```

#### 列出用户团队 [#列出用户团队]

列出用户所属的所有团队。默认针对当前用户，并返回该用户所属的每个组织中的团队。

* 传入 `userId` 可列出其他成员所属的团队。此操作受目标组织中 `member:update` 权限的限制。
* 传入 `organizationId` 可将结果限定为单个组织，无需切换会话的活跃组织。省略时，查询其他用户将使用会话的活跃组织。

**Endpoint:** `GET /organization/list-user-teams`

### Client Side

```ts
const { data, error } = await authClient.organization.listUserTeams({
    query: {
        userId, // 要列出其团队的用户 ID。默认为当前会话用户。
        organizationId, // 用于限定团队列表范围的组织 ID。对自身进行查询时若省略，则返回该用户所属的每个组织中的团队。查询其他用户时，则回退到会话的活跃组织。
    },
});
```

### Server Side

```ts
const data = await auth.api.listUserTeams({
    query: {
        userId, // 要列出其团队的用户 ID。默认为当前会话用户。
        organizationId, // 用于限定团队列表范围的组织 ID。对自身进行查询时若省略，则返回该用户所属的每个组织中的团队。查询其他用户时，则回退到会话的活跃组织。
    },
    // This endpoint requires session cookies.
    headers: await headers(),
});
```

### Type Definition

```ts
type listUserTeams = {
  /**
   * 要列出其团队的用户 ID。默认为当前会话用户。
   */
  userId?: string
  /**
   * 用于限定团队列表范围的组织 ID。对自身进行查询时若省略，则返回该用户所属的每个组织中的团队。查询其他用户时，则回退到会话的活跃组织。
   */
  organizationId?: string
}
```

#### 列出团队成员 [#列出团队成员]

列出指定团队的成员。

**Endpoint:** `POST /organization/list-team-members`

### Client Side

```ts
const { data, error } = await authClient.organization.listTeamMembers({
    query: {
        teamId: "team-id", // 应返回其成员的团队。如果未提供此项，则返回当前活跃团队的成员。
    },
});
```

### Server Side

```ts
const data = await auth.api.listTeamMembers({
    query: {
        teamId: "team-id", // 应返回其成员的团队。如果未提供此项，则返回当前活跃团队的成员。
    },
    // This endpoint requires session cookies.
    headers: await headers(),
});
```

### Type Definition

```ts
type listTeamMembers = {
    /**
     * 应返回其成员的团队。如果未提供此项，则返回当前活跃团队的成员。
     */
    teamId?: string = "team-id"
}
```

#### 添加团队成员 [#添加团队成员]

将成员添加到团队。

**Endpoint:** `POST /organization/add-team-member`

### Client Side

```ts
const { data, error } = await authClient.organization.addTeamMember({
    teamId: "team-id", // required, 用户应加入的团队。
    userId: "user-id", // required, 要添加为成员的用户 ID。
});
```

### Server Side

```ts
const data = await auth.api.addTeamMember({
    body: {
        teamId: "team-id", // required, 用户应加入的团队。
        userId: "user-id", // required, 要添加为成员的用户 ID。
    },
    // This endpoint requires session cookies.
    headers: await headers(),
});
```

### Type Definition

```ts
type addTeamMember = {
    /**
     * 用户应加入的团队。
     */
    teamId: string = "team-id"
    /**
     * 要添加为成员的用户 ID。
     */
    userId: string = "user-id"
}
```

#### 移除团队成员 [#移除团队成员]

从团队中移除成员。

**Endpoint:** `POST /organization/remove-team-member`

### Client Side

```ts
const { data, error } = await authClient.organization.removeTeamMember({
    teamId: "team-id", // required, 要从中移除用户的团队。
    userId: "user-id", // required, 要从团队中移除的用户。
});
```

### Server Side

```ts
const data = await auth.api.removeTeamMember({
    body: {
        teamId: "team-id", // required, 要从中移除用户的团队。
        userId: "user-id", // required, 要从团队中移除的用户。
    },
    // This endpoint requires session cookies.
    headers: await headers(),
});
```

### Type Definition

```ts
type removeTeamMember = {
    /**
     * 要从中移除用户的团队。
     */
    teamId: string = "team-id"
    /**
     * 要从团队中移除的用户。
     */
    userId: string = "user-id"
}
```

### 团队权限 [#团队权限]

团队使用组织权限体系。管理团队需要以下权限：

* `team:create` - 创建新团队
* `team:update` - 更新团队详情
* `team:delete` - 移除团队

默认情况下：

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

### 团队配置选项 [#团队配置选项]

团队功能支持以下配置：

* `maximumTeams`：限制每个组织的团队数量

  ```ts
  teams: {
    enabled: true,
    maximumTeams: 10 // 固定数量
    // 或
    maximumTeams: async ({ organizationId, session }, ctx) => {
      // 基于组织计划动态限制
      const plan = await getPlan(organizationId)
      return plan === 'pro' ? 20 : 5
    },
    maximumMembersPerTeam: 10 // 固定数量
    // 或
    maximumMembersPerTeam: async ({ teamId, session, organizationId }, ctx) => {
      // 基于团队计划动态限制
      const plan = await getPlan(organizationId, teamId)
      return plan === 'pro' ? 50 : 10
    },
  }
  ```

  接受团队邀请、将现有组织成员添加到团队，以及通过 `teamId` 添加新组织成员时，都会强制执行 `maximumMembersPerTeam` 限制。

* `allowRemovingAllTeams`：控制是否可以移除最后一个团队
  ```ts
  teams: {
    enabled: true,
    allowRemovingAllTeams: false // 禁止移除最后一个团队
  }
  ```

### 团队成员 [#团队成员]

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

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

用户接受邀请后会加入指定团队。

### 数据库模式 [#数据库模式]

启用团队时，数据库中将新增 `team` 和 `teamMember` 表。

表名：`team`



<DatabaseTable name="team" fields="teamsFeatureTeamTableFields" />

表名：`teamMember`



<DatabaseTable name="teamMember" fields="teamsFeatureTeamMemberTableFields" />

## 模式 [#模式]

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

### 组织 [#组织-1]

表名：`organization`。



<DatabaseTable name="organization" fields="organizationTableFields" />

### 成员 [#成员-1]

表名：`member`



<DatabaseTable name="member" fields="memberTableFields" />

### 邀请 [#邀请-1]

表名：`invitation`



<DatabaseTable name="invitation" fields="invitationTableFields" />

启用团队时，需要在邀请表添加如下字段：



<DatabaseTable name="invitation" fields="invitationTeamIdFields" />

### 会话 [#会话]

表名：`session`

需向会话表中添加两个字段，用于存储活跃组织 ID 和活跃团队 ID。



<DatabaseTable name="session" fields="sessionActiveOrganizationFields" />

### 组织角色（可选） [#组织角色可选]

表名：`organizationRole`



<DatabaseTable name="organizationRole" fields="organizationRoleTableFields" />

### 团队（可选） [#团队可选]

表名：`team`



<DatabaseTable name="team" fields="optionalTeamTableFields" />

表名：`teamMember`



<DatabaseTable name="teamMember" fields="teamsFeatureTeamTableFields0" />

表名：`邀请`



<DatabaseTable name="invitation" fields="teamsFeatureTeamTableFields1" />

### 自定义模式 [#自定义模式]

若需更改表名或字段，可传递 `schema` 选项给组织插件。

```ts title="auth.ts"
import { betterAuth } from "better-auth";
import { organization } from "better-auth/plugins";

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

#### 额外字段 [#额外字段-1]

从 [Better Auth v1.3](https://github.com/better-auth/better-auth/releases/tag/v1.3.0) 起，您可轻松为 `organization`、`invitation`、`member` 和 `team` 表添加自定义字段。

添加额外字段后，相应 API 端点会自动接收和返回这些字段。比如在 `organization` 表中添加字段，`createOrganization` 接口会支持请求体和响应中包含该字段。

```ts title="auth.ts"
import { betterAuth } from "better-auth";
import { organization } from "better-auth/plugins";

const auth = betterAuth({
  plugins: [
    organization({
      schema: {
        organization: {
          additionalFields: {
            myCustomField: {
              // [!code highlight]
              type: "string", // [!code highlight]
              input: true, // [!code highlight]
              required: false, // [!code highlight]
            }, // [!code highlight]
          },
        },
      },
    }),
  ],
});
```

若要推断额外字段，可使用 `inferOrgAdditionalFields` 函数。它会根据 auth 对象类型推断。

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

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

若无法导入 auth 类型，也可传入 schema 对象来推断。

```ts title="auth-client.ts"
import { createAuthClient } from "better-auth/client";
import {
  inferOrgAdditionalFields,
  organizationClient,
} from "better-auth/client/plugins";

const client = createAuthClient({
  plugins: [
    organizationClient({
      schema: inferOrgAdditionalFields({
        organization: {
          // [!code highlight]
          additionalFields: {
            newField: {
              // [!code highlight]
              type: "string", // [!code highlight]
            }, // [!code highlight]
          },
        },
      }),
    }),
  ],
});
```

#### 示例用法 [#示例用法]

```ts
await client.organization.create({
  name: "Test",
  slug: "test",
  newField: "123", // 允许
  //@ts-expect-error - 不存在字段
  unavailableField: "123", // 不允许
});
```

## 选项 [#选项]

**allowUserToCreateOrganization**: `boolean` | `((user: User) => Promise<boolean> | boolean)` - 决定用户是否可创建组织的函数。默认 `true`。设置 `false` 禁止创建。

**organizationLimit**: `number` | `((user: User) => Promise<boolean> | boolean)` - 用户允许创建的最大组织数。默认无限制。传函数时，函数应返回 `true` 表示已达限制（禁止新建），返回 `false` 表示未达限制（允许新建）。

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

**membershipLimit**: `number` | `((user: User, organization: Organization) => Promise<number> | number)` - 组织内允许的最大成员数。默认 100。

**sendInvitationEmail**: `async (data) => Promise<void>` - 发送邀请邮件的异步函数。

**invitationExpiresIn** : `number` - 邀请链接有效时间（秒），默认 48 小时（2 天）。

**cancelPendingInvitationsOnReInvite**: `boolean` - 如果用户已被邀请，是否取消待处理邀请。默认 `false`。

**invitationLimit**: `number` | `((user: User) => Promise<boolean> | boolean)` - 用户允许的最大邀请数。默认 100。

**requireEmailVerificationOnInvitation**: `boolean | undefined` - 是否在受邀者调用带有邀请 ID 的邀请相关接口（`acceptInvitation`、`rejectInvitation`、`getInvitation`）之前要求邮箱验证。若未设置，Better Auth 会对内置的、不可见的邀请 ID 保持正常的邮件邀请流程，包括默认生成器以及 `advanced.database.generateId: "uuid"`。对于外部可控或可预测的邀请 ID，例如 `advanced.database.generateId: "serial"` / `false` 或自定义 ID 生成方式，则会要求验证。当邀请 ID 可能在受邀用户邮箱之外可见、组织邀请列表会向成员公开，或者你希望已验证邮箱作为按 ID 执行邀请操作的所有权证明时，请将此选项设为 `true`。客户端侧的 `listUserInvitations` 始终需要已验证的会话邮箱，因为它会从会话邮箱中枚举邀请 ID。

