Organisations (B2B SaaS)
STOP — Prérequis du Tableau de bord uniquement. Les Organisations doivent être activées dans le Tableau de bord Clerk avant que toute API, hook ou composant lié à org fonctionne. Ouvrez Tableau de bord → Paramètres Organisations et activez Organisations. Choisissez délibérément le mode Adhésion :
Membership required(par défaut depuis 2025-08-22) achemine les utilisateurs connectés via la tâchechoose-organizationet désactive les comptes personnels, tandis queMembership optionalmaintient les comptes personnels disponibles pour la coexistence B2C + B2B. Choisissezoptionalsi vous avez besoin d'abonnements personnels aux côtés d'abonnements org.Version : Cette skill cible les SDKs actuels (
@clerk/nextjsv7+,@clerk/reactv6+ — Core 3). Les différences Core 2 sont notées en ligne avec des appels> **Core 2 ONLY (skip if current SDK):**— consultez la skillclerkpour le tableau de version complet.
Démarrage rapide
- Activez Organisations — Tableau de bord → Paramètres Organisations. Choisissez
Membership required(B2B uniquement) ouMembership optional(B2C + B2B). Tableau de bord uniquement ; pas de chemin CLI. - Créez une org — via
<OrganizationSwitcher />,<CreateOrganization />, ou programmatiquement avecclerkClient().organizations.createOrganization(). - Protégez les routes — lisez
orgId/orgSlugdepuisauth()et contrôlez avechas({ role })ouhas({ permission }). - Gérez les membres — envoyez des invitations via l'API Backend ou l'onglet
<OrganizationProfile />intégré. - Limitez l'adhésion — définissez
maxAllowedMembershipsà la création de l'org ou choisissez un Plan de facturation limité en sièges (voir skillclerk-billing).
De quoi avez-vous besoin ?
| Tâche | Référence |
|---|---|
| Catalogue de permissions système, rôles personnalisés, ensembles de rôles | references/roles-permissions.md |
| Cycle de vie des invitations (créer, lister, révoquer, UI intégrée) | references/invitations.md |
| Configuration SSO Enterprise, accès aux champs de fournisseur, vérification de domaine | references/enterprise-sso.md |
| Adaptations Next.js pour les orgs (middleware rôle/permission, invariants slug, écritures scoped orgId) | references/nextjs-patterns.md |
Références
| Référence | Description |
|---|---|
references/roles-permissions.md |
Rôles par défaut + personnalisés, catalogue des Permissions Système, nommage des permissions |
references/invitations.md |
API Backend pour les invitations + UI intégrée |
references/enterprise-sso.md |
SAML/OIDC par org, vérification de domaine, accès correct aux champs |
references/nextjs-patterns.md |
Adaptations Next.js spécifiques aux orgs. Pour les patterns Next.js génériques, voir la skill clerk-nextjs-patterns. |
Raccourcis du Tableau de bord
| Action | URL |
|---|---|
| Activez Organisations + mode Adhésion | https://dashboard.clerk.com/last-active?path=organizations-settings |
| Gérez les rôles + permissions | https://dashboard.clerk.com/last-active?path=organizations-settings/roles |
| Créez/modifiez une organisation | https://dashboard.clerk.com/last-active?path=organizations |
| Webhooks pour les événements org | https://dashboard.clerk.com/last-active?path=webhooks |
Documentation
- Aperçu
- Configurer + activer
- Rôles et permissions
- Vérifier l'accès
- Invitations
- OrganizationSwitcher
- Domaines vérifiés
- SSO Enterprise
Patterns clés
Les exemples utilisent @clerk/nextjs par défaut. Pour d'autres frameworks, remplacez l'import par @clerk/react (Vite/CRA), @clerk/astro/components, @clerk/vue, @clerk/expo, @clerk/react-router, ou @clerk/tanstack-react-start — les APIs au niveau des features (has(), orgId, <OrganizationSwitcher />, <Show>) sont identiques dans les SDKs. Les patterns spécifiques au framework (middleware, redirects) se trouvent dans references/nextjs-patterns.md.
1. Lire l'Organisation depuis Auth
Accès côté serveur à l'organisation active :
import { auth } from '@clerk/nextjs/server'
const { orgId, orgSlug, orgRole } = await auth()
if (!orgId) {
// l'utilisateur n'a pas d'org active — soit aucune, soit en train de consulter le Compte Personnel
}
auth() est spécifique à Next.js. Accesseurs côté serveur équivalents par SDK : auth(event) (Nuxt via event.context.auth()), context.locals.auth() (Astro), getAuth(req) (Express, après clerkMiddleware()). Côté client : useAuth() (SDKs basés sur React) ou composables (Vue/Nuxt). Tous retournent la même forme orgId / orgSlug / orgRole.
2. Routes dynamiques avec Slug Org
Le pattern route-par-org fonctionne dans tout framework supportant les routes dynamiques basées sur fichiers. Exemple Next.js :
app/orgs/[slug]/page.tsx
app/orgs/[slug]/settings/page.tsx
Vérifiez toujours que le slug d'URL correspond au slug d'org actif — sinon les utilisateurs peuvent accéder à /orgs/other-org/... avec un orgSlug obsolète dans leur session :
export default async function OrgPage({ params }: { params: { slug: string } }) {
const { orgSlug } = await auth()
if (orgSlug !== params.slug) {
redirect('/dashboard') // ou quel que soit votre flux « pas d'accès »
}
return <div>Bienvenue chez {orgSlug}</div>
}
3. Contrôle d'accès basé sur les rôles
const { has } = await auth()
if (!has({ role: 'org:admin' })) {
return <div>Accès administrateur requis</div>
}
Les vérifications de permission utilisent la même surface has() :
if (!has({ permission: 'org:sys_memberships:manage' })) {
redirect('/unauthorized')
}
Convention de nommage des permissions. Les Permissions Système commencent par org:sys_ ; les Permissions personnalisées utilisent org:<resource>:<action>. Le catalogue complet des Permissions Système se trouve dans references/roles-permissions.md — la liste courte est :
org:sys_memberships:{read, manage}org:sys_profile:{manage, delete}org:sys_domains:{read, manage}org:sys_billing:{read, manage}
N'inventez PAS de noms comme org:create, org:manage_members, org:update_metadata — ce ne sont pas de vrais slugs de permission. Consultez references/roles-permissions.md pour les rôles personnalisés et le tableau des permissions.
4. Rendu conditionnel avec <Show>
import { Show } from '@clerk/nextjs'
<Show when={{ role: 'org:admin' }}>
<AdminPanel />
</Show>
<Show when={{ permission: 'org:sys_memberships:manage' }}>
<MembersTab />
</Show>
Core 2 ONLY (skip if current SDK): Utilisez
<Protect role="org:admin">/<Protect permission="...">à la place de<Show>.<Show>a remplacé à la fois<Protect>et<SignedIn>/<SignedOut>en Core 3.
Syntaxe de template Astro pour le même composant (importé depuis @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 clés :
hidePersonal: boolean— masquez l'option Compte Personnel. Par défautfalse. Passeztruepour les apps B2B uniquement.afterCreateOrganizationUrl,afterSelectOrganizationUrl,afterLeaveOrganizationUrl,afterSelectPersonalUrl— hooks de navigation.:slugest substitué à l'exécution.createOrganizationMode,organizationProfileMode—'modal' | 'navigation'(par défaut'modal').
La liste complète des props se trouve dans la référence du composant.
6. Tâche de session — Choisir une Organisation
Quand Membership required est activé (par défaut), les utilisateurs sans org sont acheminés via une tâche de session choose-organization après la connexion. Clerk gère cela automatiquement dans <SignIn />, mais vous pouvez héberger l'UI vous-même :
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 est livré en tant que composant importé dans les SDKs basés sur React (@clerk/nextjs, @clerk/react, @clerk/react-router, @clerk/tanstack-react-start). Pour le SDK Frontend JS (@clerk/clerk-js), l'équivalent est clerk.mountTaskChooseOrganization(node) / clerk.unmountTaskChooseOrganization(node).
Core 2 ONLY (skip if current SDK): Les tâches de session ne sont pas disponibles. Forcez une sélection d'org à la connexion en redirigeant vers une page qui affiche
<OrganizationSwitcher hidePersonal />.
Rôles par défaut + Permissions Système
| Rôle | Signification par défaut |
|---|---|
org:admin |
Accès complet — toutes les Permissions Système, peut gérer org + adhésions |
org:member |
Permissions lecture membres + lecture facturation uniquement |
Vous pouvez créer jusqu'à 10 rôles personnalisés par instance dans Tableau de bord → Organisations → Rôles & Permissions. Rôle-par-org est contrôlé via Ensembles de rôles — consultez references/roles-permissions.md pour le modèle complet (rôles personnalisés, paramètres rôle Créateur/Par défaut, ensembles de rôles, et catalogue des Permissions Système).
Vérifications de facturation
has() supporte aussi les vérifications de plan et de feature quand Clerk Billing est activé :
const { has } = await auth()
has({ plan: 'gold' }) // plan d'abonnement
has({ feature: 'widgets' }) // droit de feature
Core 2 ONLY (skip if current SDK):
has()ne supporte queroleetpermission. Les vérifications de facturation ne sont pas disponibles.
Consultez clerk-billing pour la surface de Facturation complète et le modèle de plan limité en sièges.
SSO Enterprise
SAML/OIDC par org. Configuré dans Tableau de bord → Configurer → Connexions Enterprise (ou par org : Organisations → sélectionnez org → Connexions SSO). La connexion SSO possède son domaine directement ; aucun Domaine Vérifié séparé n'est requis (et les deux features s'excluent mutuellement sur le même domaine). Jointure automatique à la première connexion SSO utilise JIT Provisioning, pas les Domaines Vérifiés. Fait clé : le champ provider se trouve sur enterpriseConnection, pas directement sur enterpriseAccounts[0]. Consultez references/enterprise-sso.md pour le flux complet et l'accès correct aux champs.
// Nom de stratégie pour SSO Enterprise (Core 3)
strategy: 'enterprise_sso'
Core 2 ONLY (skip if current SDK): Utilise
strategy: 'saml'etuser.samlAccountsà la place deuser.enterpriseAccounts.
Pièges
maxAllowedMemberships limite les sièges
const clerk = await clerkClient()
await clerk.organizations.createOrganization({
name: 'Acme Corp',
createdBy: userId,
maxAllowedMemberships: 10,
})
// Mettez à jour plus tard :
await clerk.organizations.updateOrganization(orgId, {
maxAllowedMemberships: 25,
})
Pour les limites de sièges basées sur les niveaux liées à un abonnement, utilisez un Plan de facturation limité en sièges (voir clerk-billing).
La facturation contrôle les Permissions au niveau Feature
Quand Clerk Billing est activé, has({ permission: 'org:posts:edit' }) retourne false si la Feature associée à cette permission n'est pas incluse dans le Plan actif de l'organisation — même si l'utilisateur a la Permission assignée via son rôle. Assurez-vous que la Feature est attachée au Plan actif dans Tableau de bord → Facturation → Plans → Features.
Les mises à jour de métadonnées REMPLACENT, ne fusionnent pas
updateOrganization({ publicMetadata }) remplace toutes les métadonnées publiques. Lisez d'abord, étalez, puis écrivez :
const org = await clerk.organizations.getOrganization({ organizationId: orgId })
await clerk.organizations.updateOrganization(orgId, {
publicMetadata: { ...org.publicMetadata, newField: 'value' },
})
S'applique identiquement à privateMetadata et aux métadonnées utilisateur via clerkClient.users.updateUser.
Signatures d'erreur (diagnostiquez rapidement)
La plupart des défaillances « liées à org » sont des configuration, pas du code. Ne modifiez pas les composants avant de vérifier ceux-ci :
| Erreur / symptôme | Cause racine | Correction |
|---|---|---|
orgId / orgSlug est undefined pour un utilisateur connecté |
Organisations non activées pour cette instance, OU l'utilisateur n'a pas d'org active (compte personnel) | Activez dans Tableau de bord → Organisations ; vérifiez le mode Adhésion ; affichez <OrganizationSwitcher /> |
has({ permission: 'org:manage_members' }) toujours false |
Utilisation d'un slug de permission inventé | Utilisez org:sys_memberships:manage (voir le catalogue roles-permissions.md) |
has({ role }) retourne false mais l'utilisateur ressemble à un administrateur |
Jeton de session obsolète après changement de rôle | Re-connectez-vous, ou rafraîchissez la session : await clerk.session?.reload() |
has({ permission }) false même avec le rôle assigné |
Feature non attachée au Plan actif (la facturation contrôle les permissions) | Tableau de bord → Facturation → Plans → attachez Feature |
<OrganizationSwitcher /> n'affiche pas « Compte Personnel » |
Mode Membership required activé (par défaut depuis 22 août 2025) |
Tableau de bord → Paramètres Organisations → Membership optional |
TaskChooseOrganization lance « cannot render when a user doesn't have current session tasks » |
Affiché en dehors d'un contexte de tâche de session choose-organization |
Enveloppez dans une route de tâche de session choose-organization uniquement ; n'affichez pas sans conditions |
enterpriseAccounts[0].provider est undefined |
Accès à provider au mauvais niveau d'imbrication |
Utilisez user.enterpriseAccounts[0].enterpriseConnection?.provider |
Pattern d'autorisation (Exemple complet)
Composant serveur protégeant une page d'admin scoped par slug :
import { auth } from '@clerk/nextjs/server'
import { redirect } from 'next/navigation'
export default async function AdminPage({ params }: { params: { slug: string } }) {
const { orgSlug, has } = await auth()
if (orgSlug !== params.slug) redirect('/dashboard')
if (!has({ role: 'org:admin' })) redirect(`/orgs/${orgSlug}`)
return <div>Paramètres d'administration pour {orgSlug}</div>
}
Pour la protection au niveau middleware (Next.js), consultez references/nextjs-patterns.md.
Invitations (forme courte)
Envoyez depuis une action serveur ou un gestionnaire de route :
import { clerkClient, auth } from '@clerk/nextjs/server'
export async function inviteMember(organizationId: string, emailAddress: string, role: string) {
const { userId, has } = await auth()
if (!userId) throw new Error('Not signed in')
if (!has({ permission: 'org:sys_memberships:manage' })) {
throw new Error('Not authorized to invite members')
}
const clerk = await clerkClient()
return clerk.organizations.createOrganizationInvitation({
organizationId,
inviterUserId: userId, // requis selon l'API Backend
emailAddress,
role, // p.ex. 'org:admin' ou 'org:member'
redirectUrl: 'https://yourapp.com/accept-invite',
})
}
Le cycle de vie complet (lister, révoquer, créer en masse, UI <OrganizationProfile /> intégrée) se trouve dans references/invitations.md.
Flux de travail
- Activez — Organisations + mode Adhésion dans le Tableau de bord
- Créez une org — via composant UI ou API Backend
- Invitez des membres — API Backend ou UI intégrée, avec
inviterUserId - Contrôlez l'accès —
has({ role })/has({ permission })avec les noms canoniquesorg:sys_* - Scoped les routes —
orgSlug === params.slugsur chaque page protégée - Changez d'org —
<OrganizationSwitcher />gère tout le flux
Voir aussi
clerk-setup— Installation initiale de Clerkclerk-billing— Plans limités en sièges, facturation par plan,has({ plan })/has({ feature })clerk-webhooks— Synchronisez les événements org à votre base de données (organization.created,organizationMembership.*)clerk-backend-api— Référence API Backend complèteclerk-nextjs-patterns— Middleware spécifique au framework, actions serveur, caching