clerk-orgs について
Clerk Organizations を使って B2B またはマルチテナントアプリを構築する開発者向けのスキルです。組織の設定、メンバー管理、ロールと権限、エンタープライズ SSO、CLI と API による管理を扱います。
主な機能
- 01組織の有効化とメンバーシップ方式の選択
- 02メンバーと招待の管理
- 03ロールと権限によるアクセス制御
- 04エンタープライズ SSO とドメイン検証
- 05CLI と API による組織管理
活用シーン
- 01B2B アプリの組織とメンバーシップを設定する
- 02組織のロールや権限に応じてアクセスを制限する
- 03CLI で組織を作成し招待を管理する
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ clerk/ skills --skill clerk-orgsインストール後、Claude Code で/clerk-orgsを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
evals/evals.jsonreferences/enterprise-sso.mdinvitations.mdnextjs-patterns.mdroles-permissions.md詳細
Organizations(B2B SaaS)
停止 — 前提条件です。 組織関連の API、フック、コンポーネントを使用する前に、Organizations を有効にする必要があります。方法は 2 つあります。(1)ダッシュボード → Organizations の設定、または(2)
clerk enable orgs(下記の「エージェントファースト:プログラムによる組織管理」を参照)。メンバーシップモードは慎重に選択してください。Membership required(2025-08-22 以降のデフォルト)では、サインインしたユーザーはchoose-organizationタスクを経由し、個人アカウントは無効になります。一方、Membership optionalでは個人アカウントを利用できるため、B2C と B2B を併用できます。組織のサブスクリプションと並行して個人向けサブスクリプションも必要な場合は、optionalを選択してください。バージョン:このスキルは、現在の SDK(
@clerk/nextjsv7 以降、@clerk/reactv6 以降 — Core 3)を対象としています。Core 2 との違いは、該当箇所に> **Core 2 ONLY (skip if current SDK):**の注記を付けています。すべてのバージョンの一覧については、clerkスキルを参照してください。
このアプリで Organizations を使うべきですか?
有効にする前に判断してください。プロジェクトを読み、該当する兆候を数えたうえで、開発者に確認してください。黙って Organizations を有効にしてはいけません。
このアプリがマルチテナントである兆候(Organizations を推奨):
- ユーザーをグループ化するモデル:
Team、Workspace、Tenant、Company、Account - ほとんどのテーブルで同じ外部キーを使用:
workspace_id、team_id、account_id - テナントの範囲に限定されたルート:
/[workspace]、/[slug]/settings、/t/:tenantId - UI の文言や README に「チームを招待」「メンバー」「シート」「管理者」がある
*_members結合テーブル、または独自に実装したrole/permission列- シート単位または会社単位の料金体系
弱い兆候 — 質問を提起するには十分ですが、判断するには不十分です:
- 個々のユーザー間での共有や共同作業:2 つのユーザー ID をキーとする
Share、Collaborator、またはSharedWithテーブル - テナントによるスコープがない
roleまたはpermission列 - 文言に「共同作業者」「あなたに共有」「友達を招待」がある
このアプリがシングルユーザーである兆候(推奨しない):
- 上位のコンテナがなく、共有もされていないため、すべてのテーブルが
user_idに直接ひも付いている - 招待、メンバーシップ、共有の概念がどこにもない
- 料金体系がユーザー単位、または料金がない
対応方法:
| 確認できたこと | 対応 |
|---|---|
| 強い兆候が 2 つ以上 | Organizations を推奨し、確認した兆候を示します。新規アプリの場合:clerk init --template b2b-saas。既存アプリの場合:clerk enable orgs。 |
| 強い兆候が 1 つ、または弱い兆候が 1 つ以上 | 選択肢として提示し、トレードオフを説明したうえで、開発者に選んでもらいます。個々のユーザー間の共有はマルチテナンシーではありません。2 つのユーザー ID を参照する Share テーブルにテナントはありません。ただし、そのような機能をきっかけにプロダクトが成長することはよくあります。 |
| 上記に該当しない | 話題に出さないでください。 |
確認せずに Organizations を有効にしてはいけません。 有効にすると Membership required もオンになり、サインインしたすべてのユーザーが組織選択を経由し、個人アカウントが無効になります。個人ユーザーにもサービスを提供するアプリには適していません。両方に対応する必要がある場合は、Membership optional を選択してください。
クイックスタート
- Organizations を有効にする — ダッシュボード → Organizations の設定または
clerk enable orgsを使用します(「エージェントファースト」のセクションを参照)。Membership required(B2B のみ)またはMembership optional(B2C + B2B)を選択してください。 - 組織を作成する —
<OrganizationSwitcher />、<CreateOrganization />、またはclerkClient().organizations.createOrganization()を使ったプログラムによる方法で作成します。 - ルートを保護する —
auth()からorgId/orgSlugを読み取り、has({ role })またはhas({ permission })でアクセスを制御します。 - メンバーを管理する — Backend API または組み込みの
<OrganizationProfile />タブから招待を送信します。 - メンバー数に上限を設定する — 組織の作成時に
maxAllowedMembershipsを設定するか、シート数に上限のある Billing Plan を選択します(clerk-billingスキルを参照)。
何が必要ですか?
| タスク | リファレンス |
|---|---|
| システム権限カタログ、カスタムロール、ロールセット | references/roles-permissions.md |
| 招待のライフサイクル(作成、一覧表示、取り消し、組み込み UI) | references/invitations.md |
| エンタープライズ SSO の設定、プロバイダーフィールドへのアクセス、ドメイン検証 | references/enterprise-sso.md |
| 組織向け Next.js の適用方法(ページ単位のロール/権限チェック、スラッグの不変条件、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 スキルを参照してください。 |
ダッシュボードのショートカット
| 操作 | 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 |
| 組織イベントの Webhook | https://dashboard.clerk.com/last-active?path=webhooks |
エージェント優先:組織をプログラムで管理
組織の設定(有効化トグル、メンバーシップ上限、管理者による削除、ドメイン)は、PLAPI Instance Config を介してパッチできます。組織の CRUD、メンバーシップ、招待は BAPI にあります。組織を初期設定するエージェント、インスタンス間で設定を複製する場合、または組織構成をバージョン管理する場合に便利です。
前提条件:リンク済みプロジェクト(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(インスタンスレベルのロール定義)を使用します。UX 上の同等機能については、ダッシュボードのロールエディターを参照してください。 - 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 に切り替えてください。機能レベルの API(has()、orgId、<OrganizationSwitcher />、<Show>)は、すべての SDK で共通です。フレームワーク固有のパターン(ミドルウェア、リダイレクト)については、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)(clerkMiddleware() の後の Express)です。クライアント側では、useAuth()(React ベースの SDK)またはコンポーザブル(Vue/Nuxt)を使用します。いずれも同じ orgId/orgSlug/orgRole の形式を返します。
2. 組織スラッグを使った動的ルート
組織ごとにルートを設けるパターンは、ファイルベースの動的ルートに対応するあらゆるフレームワークで機能します。Next.js の例:
app/orgs/[slug]/page.tsx
app/orgs/[slug]/settings/page.tsx
URL のスラッグがアクティブな組織のスラッグと一致することを必ず確認してください。一致しないと、セッション内の 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>
}
権限チェックでは、ダッシュボードで作成したカスタム権限にも同じ has() API を使用します。
if (!has({ permission: 'org:invoices:create' })) {
redirect('/unauthorized')
}
サーバー上で has({ permission }) が機能するのはカスタム権限のみです。システム権限(org:sys_*)はセッショントークンに含まれないため、そこでチェックすると常に false が返されます。Clerk がドキュメントで説明している <Show when={{ permission }}> による権限チェックも、カスタム権限のみが対象です。システム権限を必須にするには、それを持つロールをチェックしてください(has({ role: 'org:admin' }))。
権限の命名規則。 システム権限には org:sys_ を付け、カスタム権限には org:<resource>:<action> を使用します。システム権限の一覧は 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 のような名前を作らないでください。これらは実在する権限スラッグではありません。カスタムロールと権限の一覧については、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 ではスキップ):
<Show>の代わりに<Protect role="org:admin">/<Protect permission="...">を使用してください。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"
/>
主な props:
hidePersonal: boolean— Personal Account オプションを非表示にします。デフォルトはfalseです。B2B 専用アプリではtrueを指定してください。afterCreateOrganizationUrl、afterSelectOrganizationUrl、afterLeaveOrganizationUrl、afterSelectPersonalUrl— ナビゲーションフックです。:slugは実行時に置き換えられます。createOrganizationMode、organizationProfileMode—'modal' | 'navigation'(デフォルトは'modal')。
props の全一覧は、コンポーネントリファレンスを参照してください。
6. セッションタスク — 組織を選択する
Membership required が有効(デフォルト)な場合、組織に所属していないユーザーはサインイン後に choose-organization セッションタスクに進みます。Clerk は <SignIn /> 内でこれを自動的に処理しますが、UI を独自にホストすることもできます。
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 サインイン時の自動参加には、Verified Domains ではなく JIT Provisioning を使用します。重要な点として、provider フィールドは enterpriseAccounts[0] ではなく enterpriseConnection にあります。全体のフローと正しいフィールドの参照方法については、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 | このインスタンスで組織が有効になっていない、またはユーザーにアクティブな組織がない(個人アカウント) | ダッシュボード → Organizations で有効にします。Membership mode を確認し、<OrganizationSwitcher />を表示します |
has({ permission: ... })が常にfalse | 存在しないスラッグ(org:manage_members)、またはSystem Permission(org:sys_*)であり、has()ではチェックできない | ロール(has({ role: 'org:admin' }))またはダッシュボードで作成したカスタムPermissionを確認します(roles-permissions.mdを参照) |
has({ role })がfalseを返すが、ユーザーは管理者のように見える | ロール変更後にセッショントークンが古いままになっている | 再度サインインするか、セッションを更新します:await clerk.session?.reload() |
ロールを割り当てているのにhas({ permission })がfalse | 機能がアクティブなプランに紐付いていない(Billingが権限を制御します) | ダッシュボード → Billing → Plans → Featureを紐付けます |
<OrganizationSwitcher />に「Personal Account」が表示されない | Membership requiredモードが有効になっている(2025年8月22日以降のデフォルト) | ダッシュボード → 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を使用します |
認可パターン(完全な例)
スラッグのスコープに限定された管理ページを保護するサーバーコンポーネント:
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>
}
Cache Componentsを使用する場合、next buildを通すには隣にloading.tsxを追加してください。
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を参照してください。
ワークフロー
- 有効化 — ダッシュボードでOrganizationsとMembership modeを設定します
- 組織を作成 — UIコンポーネントまたはBackend APIを使用します
- メンバーを招待 — Backend APIまたは組み込みUIを使用し、
inviterUserIdを指定します - アクセスを制限 —
has({ role })、またはカスタムPermissionを使ったhas({ permission })を使用します。has()ではSystem Permissions(org:sys_*)をチェックできません - ルートのスコープを設定 — 保護対象のすべてのページで
orgSlug === params.slugを確認します - 組織を切り替え —
<OrganizationSwitcher />が一連のフロー全体を処理します
関連項目
clerk-setup— Clerkの初期インストールclerk-billing— シート数制限プラン、プランごとの課金、has({ plan })/has({ feature })clerk-webhooks— 組織のイベントをデータベースに同期します(organization.created、organizationMembership.*)clerk-backend-api— Backend APIの完全なリファレンスclerk-nextjs-patterns— フレームワーク固有のミドルウェア、サーバーアクション、キャッシュ