mcpField
C
clerk-orgs

clerk-orgs

github.com/clerk开发8951.5k 次安装今天更新
代码仓库

关于 clerk-orgs

面向构建 B2B 或多租户应用的开发者,介绍 Clerk Organizations 的启用、组织成员、角色权限和企业 SSO 模式。还涵盖通过 CLI 与 API 管理组织配置及成员。

主要功能

  1. 01组织启用与成员模式选择
  2. 02组织成员和邀请管理
  3. 03角色与权限访问控制
  4. 04企业 SSO 与域名验证
  5. 05CLI 和 API 组织管理

适用场景

  1. 01为 B2B 应用配置组织与成员关系
  2. 02根据组织角色或权限限制访问
  3. 03通过 CLI 创建组织并管理邀请

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/clerk/skills --skill clerk-orgs

安装后在 Claude Code 中输入/clerk-orgs确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

evals/
evals.json
references/
enterprise-sso.md
invitations.md
nextjs-patterns.md
roles-permissions.md

详细介绍

组织(B2B SaaS)

停止——前置条件。 必须先启用组织,任何与组织相关的 API、钩子或组件才能生效。两种方式:(1)Dashboard → Organizations settings,或(2)clerk enable orgs(请参阅下文“Agent 优先:以编程方式管理组织”)。请慎重选择 Membership 模式:Membership required(自 2025-08-22 起为默认设置)会将已登录用户引导至 choose-organization 任务,并禁用个人账户;Membership optional 则保留个人账户,以支持 B2C 与 B2B 并存。如果需要同时提供个人订阅和组织订阅,请选择 optional。

版本:本技能面向当前 SDK(@clerk/nextjs v7+、@clerk/react v6+ — Core 3)。Core 2 的差异会以内联提示 > **仅适用于 Core 2(当前 SDK 请跳过):** 标出——完整版本表请参阅 clerk 技能。

此应用是否应该使用组织?

启用任何功能前请先做出判断。检查项目、统计信号,然后询问开发者——不要悄悄启用组织。

表明此应用为多租户应用的信号(建议使用组织):

  • 用于对用户分组的模型:Team、Workspace、Tenant、Company、Account
  • 大多数表都使用相同的外键:workspace_id、team_id、account_id
  • 按租户划分范围的路由:/[workspace]、/[slug]/settings、/t/:tenantId
  • UI 文案或 README 中出现“邀请你的团队”、“成员”、“席位”或“管理员”
  • 存在 *_members 联接表,或手动实现的 role / permission 列
  • 按席位或按公司定价

较弱的信号——足以提出问题,但不足以做出判断:

  • 个人用户之间的共享或协作:以两个用户 ID 为键的 Share、Collaborator 或 SharedWith 表
  • 存在 role 或 permission 列,但没有对应的租户范围
  • 文案中出现“协作者”、“与你共享”或“邀请朋友”

表明此应用为单用户应用的信号(不建议使用):

  • 每张表都关联到 user_id,没有更高层级的容器,也没有共享功能
  • 完全没有邀请、成员资格或共享的概念
  • 按个人定价,或没有定价

行动方式:

发现情况应采取的行动
至少 2 个强信号建议使用组织,并指出你发现的信号。新应用:clerk init --template b2b-saas。现有应用:clerk enable orgs。
1 个强信号,或任何较弱信号将其作为一个选项提出,说明其中的取舍,并让开发者决定。个人用户之间的共享不属于多租户——指向两个用户 ID 的 Share 表并没有租户——但产品往往会从这里发展出多租户需求。
以上情况都没有不要提起。

未经询问,绝不要启用组织。 启用组织还会开启 Membership required,将每位已登录用户都引导至组织选择,并禁用个人账户。对于同时服务个人用户的任何应用,这都是错误的选择。如果应用两者都需要,应使用 Membership optional。

快速开始

  1. 启用组织——通过 Dashboard → Organizations settings 或 clerk enable orgs(请参阅“Agent 优先”一节)。选择 Membership required(仅限 B2B)或 Membership optional(B2C + B2B)。
  2. 创建组织——通过 <OrganizationSwitcher />、<CreateOrganization />,或以编程方式调用 clerkClient().organizations.createOrganization()。
  3. 保护路由——从 auth() 读取 orgId / orgSlug,并使用 has({ role }) 或 has({ permission }) 进行访问控制。
  4. 管理成员——通过后端 API 或内置的 <OrganizationProfile /> 标签页发送邀请。
  5. 限制成员人数——在创建组织时设置 maxAllowedMemberships,或选择限制席位数的 Billing Plan(请参阅 clerk-billing 技能)。

您需要什么?

任务参考资料
系统权限目录、自定义角色、角色集references/roles-permissions.md
邀请生命周期(创建、列出、撤销、内置 UI)references/invitations.md
企业 SSO 设置、提供商字段访问、域名验证references/enterprise-sso.md
面向组织的 Next.js 适配(逐页角色/权限检查、slug 不变量、按 orgId 限定范围的写入)references/nextjs-patterns.md

参考资料

参考资料说明
references/roles-permissions.md默认角色和自定义角色、系统权限目录、权限命名
references/invitations.md邀请的后端 API 和内置 UI
references/enterprise-sso.md每个组织的 SAML/OIDC、域名验证、正确的字段访问方式
references/nextjs-patterns.md专为组织设计的 Next.js 适配。通用 Next.js 模式请参阅 clerk-nextjs-patterns 技能。

Dashboard 快捷方式

操作URL
启用 Organizations 和 Membership 模式https://dashboard.clerk.com/last-active?path=organizations-settings
管理角色和权限https://dashboard.clerk.com/last-active?path=organizations-settings/roles
创建/编辑组织https://dashboard.clerk.com/last-active?path=organizations
组织事件的 Webhookshttps://dashboard.clerk.com/last-active?path=webhooks

Agent 优先:以编程方式管理组织

组织设置(启用开关、成员上限、管理员删除、域名)可通过 PLAPI Instance Config 进行修补。组织的 CRUD、成员关系和邀请由 BAPI 管理。适用于 Agent 创建组织、在多个实例间复制设置或对组织结构进行版本控制。

前置条件:已关联项目(clerk auth login 和 clerk link,参阅 clerk-cli)——或者通过 clerk init 创建的未认领应用:无需登录即可使用 clerk enable orgs 和通过 clerk api 执行组织 CRUD。

通过 CLI 启用 Organizations 和相关设置
clerk enable orgs

如需设置其他选项(成员上限、已验证域名、管理员删除),请修补实例配置:

clerk api --platform PATCH /v1/platform/applications/<app_id>/instances/<ins_id>/config \
  -d '{"organization_settings":{"max_allowed_memberships":50,"domains_enabled":true,"admin_delete_enabled":true}}'
创建/列出/删除组织(BAPI)
# Create:
clerk api -X POST /v1/organizations \
  -d '{"name":"Acme","slug":"acme","created_by":"user_xxx","max_allowed_memberships":10}'

# List:
clerk api '/v1/organizations?limit=20'

# Get one:
clerk api /v1/organizations/<org_id>

# Update:
clerk api -X PATCH /v1/organizations/<org_id> -d '{"name":"Acme Inc."}'

# Delete:
clerk api -X DELETE /v1/organizations/<org_id>
成员关系
# Add a user to an org:
clerk api -X POST /v1/organizations/<org_id>/memberships \
  -d '{"user_id":"user_xxx","role":"org:admin"}'

# List members:
clerk api '/v1/organizations/<org_id>/memberships?limit=50'

# Update role:
clerk api -X PATCH /v1/organizations/<org_id>/memberships/<user_id> \
  -d '{"role":"org:member"}'

# Remove:
clerk api -X DELETE /v1/organizations/<org_id>/memberships/<user_id>
邀请
# Send:
clerk api -X POST /v1/organizations/<org_id>/invitations \
  -d '{"email_address":"[email protected]","role":"org:member","redirect_url":"https://app.com/accept"}'

# List pending:
clerk api '/v1/organizations/<org_id>/invitations?status=pending'

# Revoke:
clerk api -X POST /v1/organizations/<org_id>/invitations/<inv_id>/revoke \
  -d '{"requesting_user_id":"user_xxx"}'
备注
  • 此处处理组织配置和 CRUD。组织的订阅/账单(组织方案、按席位数量定价)通过 clerk-billing 技能处理。
  • 角色和权限目录可在 references/roles-permissions.md 中编辑。创建自定义角色需使用 clerk config patch(实例级角色定义)——可参阅 Dashboard 的角色编辑器,了解对应的 UI 操作。
  • SSO/已验证域名配置请参阅 references/enterprise-sso.md。

文档

关键模式

示例默认使用 @clerk/nextjs。对于其他框架,将导入替换为 @clerk/react(Vite/CRA)、@clerk/astro/components、@clerk/vue、@clerk/expo、@clerk/react-router 或 @clerk/tanstack-react-start——各 SDK 中的功能级 API(has()、orgId、<OrganizationSwitcher />、<Show>)完全相同。框架特有的模式(中间件、重定向)见 references/nextjs-patterns.md。

1. 从身份验证中读取组织

在服务端访问当前组织:

import { auth } from '@clerk/nextjs/server'

const { orgId, orgSlug, orgRole } = await auth()
if (!orgId) {
  // user has no active org — either not in any, or viewing Personal Account
}

auth() 是 Next.js 专用函数。各 SDK 提供的等效服务端访问器包括:auth(event)(Nuxt,通过 event.context.auth())、context.locals.auth()(Astro)、getAuth(req)(Express,在 clerkMiddleware() 之后)。客户端:useAuth()(基于 React 的 SDK)或组合式函数(Vue/Nuxt)。这些方法均返回相同结构的 orgId / orgSlug / orgRole。

2. 使用组织 Slug 的动态路由

按组织设置路由的模式适用于任何支持基于文件的动态路由的框架。Next.js 示例:

app/orgs/[slug]/page.tsx
app/orgs/[slug]/settings/page.tsx

务必确认 URL 中的 slug 与当前组织的 slug 相符,否则用户可能会在会话中的 orgSlug 已过期时访问 /orgs/other-org/...:

import { auth } from '@clerk/nextjs/server'
import { redirect } from 'next/navigation'

export default async function OrgPage({ params }: { params: Promise<{ slug: string }> }) {
  const { slug } = await params
  const { orgSlug } = await auth()
  if (orgSlug !== slug) {
    redirect('/dashboard')  // or whatever your "no-access" flow is
  }
  return <div>Welcome to {orgSlug}</div>
}

在 Next.js 中,若页面像此处一样使用 redirect() 控制渲染,请在页面旁添加 loading.tsx:启用 Cache Components(create-next-app 的默认设置)时,在 <Suspense> 边界外读取请求数据会导致 next build 失败。

3. 基于角色的访问控制
const { has } = await auth()

if (!has({ role: 'org:admin' })) {
  return <div>Admin access required</div>
}

对于你在 Dashboard 中创建的自定义 Permissions,也可以使用相同的 has() 接口检查权限:

if (!has({ permission: 'org:invoices:create' })) {
  redirect('/unauthorized')
}

在服务端,has({ permission }) 仅适用于自定义 Permissions:System Permissions(org:sys_*)不会包含在会话令牌中,因此在那里检查它们始终会返回 false。Clerk 文档中,<Show when={{ permission }}> 也仅用于检查自定义 Permissions。若要要求 System Permission,请检查拥有该权限的角色(has({ role: 'org:admin' }))。

权限命名约定。 System Permissions 以 org:sys_ 为前缀;自定义 Permissions 使用 org:<resource>:<action>。完整的 System Permissions 目录位于 references/roles-permissions.md,简要列表如下:

  • org:sys_memberships:{read, manage}
  • org:sys_profile:{manage, delete}
  • org:sys_domains:{read, manage}
  • org:sys_billing:{read, manage}

切勿编造 org:create、org:manage_members、org:update_metadata 之类的名称——它们不是有效的权限 slug。自定义角色和权限表请参阅 references/roles-permissions.md。

4. 使用 <Show> 进行条件渲染

在 Next.js Server Component 中,<Show> 会从请求中读取会话,因此应将它放在 <Suspense> 中。在 Client Component 中,它会读取客户端身份验证状态,无需使用边界。

import { Show } from '@clerk/nextjs'
import { Suspense } from 'react'

<Suspense>
  <Show when={{ role: 'org:admin' }}>
    <AdminPanel />
  </Show>

  <Show when={{ permission: 'org:invoices:create' }}>
    <NewInvoiceButton />
  </Show>
</Suspense>

仅限 Core 2(当前 SDK 请跳过): 使用 <Protect role="org:admin"> / <Protect permission="..."> 代替 <Show>。在 Core 3 中,<Show> 取代了 <Protect> 和 <SignedIn> / <SignedOut>。

同一组件在 Astro 模板中的语法(从 @clerk/astro/components 导入):

<Show when={{ role: 'org:admin' }}>
  <AdminPanel />
</Show>
5. OrganizationSwitcher
import { OrganizationSwitcher } from '@clerk/nextjs'

<OrganizationSwitcher
  hidePersonal
  afterCreateOrganizationUrl="/orgs/:slug/dashboard"
  afterSelectOrganizationUrl="/orgs/:slug/dashboard"
/>

主要属性:

  • hidePersonal: boolean — 隐藏 Personal Account 选项。默认值为 false。仅面向 B2B 的应用请传入 true。
  • afterCreateOrganizationUrl、afterSelectOrganizationUrl、afterLeaveOrganizationUrl、afterSelectPersonalUrl — 导航钩子。:slug 会在运行时替换。
  • createOrganizationMode、organizationProfileMode — 'modal' | 'navigation'(默认值为 'modal')。

完整属性列表请参阅组件参考。

6. 会话任务 — 选择组织

启用 Membership required(默认设置)时,没有组织的用户登录后会进入 choose-organization 会话任务。Clerk 会在 <SignIn /> 中自动处理此流程,但你也可以自行托管该界面:

import { ClerkProvider } from '@clerk/nextjs'

<ClerkProvider taskUrls={{ 'choose-organization': '/session-tasks/choose-organization' }}>
  {children}
</ClerkProvider>
// app/session-tasks/choose-organization/page.tsx
import { TaskChooseOrganization } from '@clerk/nextjs'

export default function Page() {
  return <TaskChooseOrganization redirectUrlComplete="/dashboard" />
}

TaskChooseOrganization 作为导入式组件提供给基于 React 的 SDK(@clerk/nextjs、@clerk/react、@clerk/react-router、@clerk/tanstack-react-start)。对于 JS Frontend SDK(@clerk/clerk-js),对应的方法是 clerk.mountTaskChooseOrganization(node) / clerk.unmountTaskChooseOrganization(node)。

仅限 Core 2(当前 SDK 请跳过): 不支持会话任务。若要强制用户在登录时选择组织,请将其重定向到一个渲染 <OrganizationSwitcher hidePersonal /> 的页面。

默认角色 + 系统权限

角色默认含义
org:admin完全访问权限——拥有所有系统权限,可管理组织和成员资格
org:member仅可读取成员和账单权限

你可以在 Dashboard → Organizations → Roles & Permissions 中为每个实例创建最多 10 个自定义角色。每个组织的角色由 Role Sets 控制——完整模型(自定义角色、Creator/Default 角色设置、角色集和系统权限目录)请参阅 references/roles-permissions.md。

账单检查

启用 Clerk Billing 后,has() 还支持计划和功能检查:

const { has } = await auth()

has({ plan: 'gold' })        // subscription plan
has({ feature: 'widgets' })  // feature entitlement

仅限 Core 2(当前 SDK 请跳过): has() 仅支持 role 和 permission。不支持账单检查。

完整的账单功能和席位限制计划模型请参阅 clerk-billing。

企业 SSO

按组织配置 SAML/OIDC。在 Dashboard → Configure → Enterprise Connections 中配置(或按组织配置:Organizations → 选择组织 → SSO Connections)。SSO 连接直接关联其域名;无需单独的 Verified Domain(且同一域名不能同时使用这两项功能)。首次 SSO 登录时自动加入组织使用的是 JIT Provisioning,而非 Verified Domains。重要提示:provider 字段位于 enterpriseConnection 上,而不是直接位于 enterpriseAccounts[0] 上。完整流程和正确的字段访问方式请参阅 references/enterprise-sso.md。

// Strategy name for Enterprise SSO (Core 3)
strategy: 'enterprise_sso'

仅限 Core 2(当前 SDK 请跳过): 使用 strategy: 'saml' 和 user.samlAccounts,而非 user.enterpriseAccounts。

注意事项

maxAllowedMemberships 限制席位数
const clerk = await clerkClient()
await clerk.organizations.createOrganization({
  name: 'Acme Corp',
  createdBy: userId,
  maxAllowedMemberships: 10,
})

// Update later:
await clerk.organizations.updateOrganization(orgId, {
  maxAllowedMemberships: 25,
})

如需与订阅绑定的分级席位限制,请使用有席位限制的 Billing Plan(参阅 clerk-billing)。

Billing 在功能层级控制权限

启用 Clerk Billing 后,如果与该权限关联的 Feature 未包含在组织当前生效的 Plan 中,has({ permission: 'org:posts:edit' }) 将返回 false——即使用户已通过其角色获得该权限。请确保在 Dashboard → Billing → Plans → Features 中将该 Feature 添加到当前生效的 Plan。

元数据更新会替换内容,而非合并

updateOrganization({ publicMetadata }) 会覆盖所有公开元数据。请先读取,再展开,最后写入:

const org = await clerk.organizations.getOrganization({ organizationId: orgId })
await clerk.organizations.updateOrganization(orgId, {
  publicMetadata: { ...org.publicMetadata, newField: 'value' },
})

这同样适用于 privateMetadata,以及通过 clerkClient.users.updateUser 更新用户元数据的情况。

错误特征(快速诊断)

大多数“与组织相关”的故障源于配置,而非代码。在检查以下事项之前,请勿修改组件:

错误 / 症状根本原因修复方法
已登录用户的 orgId / orgSlug 为 undefined此实例未启用组织,或用户没有活跃组织(个人账户)在 Dashboard → Organizations 中启用;检查 Membership mode;显示 <OrganizationSwitcher />
has({ permission: ... }) 始终为 false使用了虚构的 slug(org:manage_members),或使用了 has() 无法检查的系统权限(org:sys_*)检查角色(has({ role: 'org:admin' })),或在 Dashboard 中创建自定义权限(参见 roles-permissions.md)
has({ role }) 返回 false,但用户看起来像管理员角色更改后,会话令牌已过期重新登录,或刷新会话:await clerk.session?.reload()
即使已分配角色,has({ permission }) 仍返回 false功能未关联到当前套餐(Billing 会控制权限)Dashboard → Billing → Plans → 关联功能
<OrganizationSwitcher /> 未显示“个人账户”已启用 Membership required 模式(自 2025 年 8 月 22 日起为默认设置)Dashboard → Organizations settings → Membership optional
TaskChooseOrganization 抛出“cannot render when a user doesn't have current session tasks”错误在 choose-organization 任务上下文之外渲染仅在 choose-organization 会话任务路由中使用;不要无条件渲染
enterpriseAccounts[0].provider 为 undefined在错误的嵌套层级访问 provider使用 user.enterpriseAccounts[0].enterpriseConnection?.provider

授权模式(完整示例)

保护 slug 作用域管理页面的服务端组件:

import { auth } from '@clerk/nextjs/server'
import { redirect } from 'next/navigation'

export default async function AdminPage({ params }: { params: Promise<{ slug: string }> }) {
  const { slug } = await params
  const { orgSlug, has } = await auth()

  if (orgSlug !== slug) redirect('/dashboard')
  if (!has({ role: 'org:admin' })) redirect(`/orgs/${orgSlug}`)

  return <div>Admin settings for {orgSlug}</div>
}

在其旁边添加 loading.tsx,以便 next build 能在 Cache Components 下通过。

有关使用 auth.protect() 进行页面级角色和权限检查(Next.js),请参阅 references/nextjs-patterns.md。

邀请(简版)

从服务端操作或路由处理程序发送:

import { clerkClient, auth } from '@clerk/nextjs/server'

export async function inviteMember(emailAddress: string, role: string) {
  const { userId, orgId, has } = await auth()

  if (!userId || !orgId) throw new Error('No active organization')
  // Inviting needs the System Permission org:sys_memberships:manage, which
  // has() can't check, so check a role that carries it.
  if (!has({ role: 'org:admin' })) {
    throw new Error('Not authorized to invite members')
  }

  const clerk = await clerkClient()
  return clerk.organizations.createOrganizationInvitation({
    organizationId: orgId,       // the active org that has() checked
    inviterUserId: userId,       // required per Backend API
    emailAddress,
    role,                        // e.g. 'org:admin' or 'org:member'
    redirectUrl: 'https://yourapp.com/accept-invite',
  })
}

完整生命周期(列表、撤销、批量创建、内置 <OrganizationProfile /> UI)请参阅 references/invitations.md。

工作流

  1. 启用 — 在 Dashboard 中启用 Organizations + Membership mode
  2. 创建组织 — 通过 UI 组件或 Backend API
  3. 邀请成员 — 通过 Backend API 或内置 UI,并提供 inviterUserId
  4. 控制访问 — 使用 has({ role }),或使用自定义权限调用 has({ permission })。has() 无法检查系统权限(org:sys_*)
  5. 限定路由范围 — 在每个受保护页面上检查 orgSlug === params.slug
  6. 切换组织 — <OrganizationSwitcher /> 会处理整个流程

另请参阅

  • clerk-setup — Clerk 初始安装
  • clerk-billing — 席位限制套餐、按套餐计费、has({ plan }) / has({ feature })
  • clerk-webhooks — 将组织事件同步到数据库(organization.created、organizationMembership.*)
  • clerk-backend-api — 完整的 Backend API 参考
  • clerk-nextjs-patterns — 特定框架的中间件、服务端操作、缓存

评论

支持 Markdown