clerk-orgs について
マルチテナントの B2B SaaS を開発するコーディングエージェント向けの Clerk Organizations スキルです。SDK の実装パターンと CLI/API による管理を扱い、組織機能やメンバーシップ方式の選択も案内します。
主な機能
- 01組織機能が必要かを評価
- 02必須または任意のメンバーシップ設定
- 03組織のロールと権限によるルート保護
- 04組織、メンバー、招待の管理
- 05CLI と API による組織設定の管理
活用シーン
- 01B2B SaaS に組織とチームメンバーを追加
- 02ロールに応じて組織ページへのアクセスを制限
- 03CLI で組織を作成しメンバーを管理
- 04個人アカウントと組織アカウントを併用
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ midudev/ autoskills --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)(event.context.auth() を使用する Nuxt)、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/... にアクセスできてしまいます。
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>
}
3. ロールベースのアクセス制御
const { has } = await auth()
if (!has({ role: 'org:admin' })) {
return <div>Admin access required</div>
}
ダッシュボードで作成したカスタム権限も、同じ has() インターフェースを使って確認します。
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> による条件付きレンダリング
import { Show } from '@clerk/nextjs'
<Show when={{ role: 'org:admin' }}>
<AdminPanel />
</Show>
<Show when={{ permission: 'org:invoices:create' }}>
<NewInvoiceButton />
</Show>
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"
/>
主なプロパティ:
hidePersonal: boolean— 個人アカウントのオプションを非表示にします。デフォルトはfalseです。B2B 専用アプリではtrueを渡します。afterCreateOrganizationUrl、afterSelectOrganizationUrl、afterLeaveOrganizationUrl、afterSelectPersonalUrl— ナビゲーションフックです。:slugは実行時に置き換えられます。createOrganizationMode、organizationProfileMode—'modal' | 'navigation'(デフォルトは'modal')です。
プロパティの全一覧はコンポーネントリファレンスにあります。
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 | このインスタンスで組織が有効になっていない、またはユーザーにアクティブな組織がない(個人アカウント) | Dashboard → Organizations で有効にします。Membership mode を確認し、<OrganizationSwitcher /> を表示します |
has({ permission: ... }) が常に false | 存在しないスラッグ(org:manage_members)、または has() では確認できない System Permission(org:sys_*) | ロール(has({ role: 'org:admin' }))または Dashboard で作成したカスタム Permission を確認します(roles-permissions.md を参照) |
has({ role }) が false を返すが、ユーザーは管理者に見える | ロール変更後にセッショントークンが古いままになっている | 再度サインインするか、セッションを更新します:await clerk.session?.reload() |
ロールを割り当てても has({ permission }) が false | アクティブな Plan に機能が紐付けられていない(Billing によって権限が制御されています) | Dashboard → Billing → Plans で Feature を追加します |
<OrganizationSwitcher /> に「Personal Account」が表示されない | 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 を使用します |
認可パターン(完全な例)
スラッグで範囲を限定した管理者ページを保護するサーバーコンポーネント:
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>
}
ページごとのロールおよび権限チェックで 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 を参照してください。
ワークフロー
- 有効化 — Dashboard で Organizations と Membership mode を有効にします
- 組織を作成 — UI コンポーネントまたは Backend API 経由で作成します
- メンバーを招待 —
inviterUserIdを指定して、Backend API または組み込み UI から招待します - アクセスを制御 —
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— ミドルウェア、サーバーアクション、キャッシュに関するフレームワーク固有の情報