Skip to content

Commit 66daa0f

Browse files
committed
docs review updates
1 parent 9307abf commit 66daa0f

File tree

4 files changed

+235
-124
lines changed

4 files changed

+235
-124
lines changed

docs/guides/organizations/metadata.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ If you've considered the limitations, and you still want to store metadata in th
5050

5151
Now that you understand organization metadata, you can:
5252

53-
- [Use organization slugs in URLs](/docs/guides/organizations/org-slugs-in-urls) for tenant-specific routing
5453
- [Add metadata to invitations](/docs/guides/organizations/invitations#invitation-metadata) to track invitation sources or assign attributes
5554
- [Create and manage organizations](/docs/guides/organizations/create-and-manage) to see metadata in action
56-
- [Authorize users](/docs/guides/secure/authorization-checks) to control access based on roles and permissions
55+
- [Control access based on roles and permissions](/docs/guides/secure/authorization-checks)
56+
- [Use organization slugs in URLs](/docs/guides/organizations/org-slugs-in-urls) for tenant-specific routing

docs/guides/organizations/quickstart.mdx

Lines changed: 229 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,12 @@
11
---
2-
title: Organizations quickstart for Next.js
3-
description: Learn how to add organizations to your Next.js app with Clerk's prebuilt components.
4-
sdk: nextjs
2+
title: Organizations quickstart
3+
description: Learn how to add organizations to your application with Clerk's prebuilt components.
54
---
65

76
Organizations let you group users with roles and permissions, enabling you to build multi-tenant B2B apps like Slack (workspaces), Linear (teams), or Vercel (projects) where users can switch between different team contexts.
87

9-
> [!NOTE]
10-
> Just getting started with Clerk and Next.js? See the [quickstart tutorial](/docs/nextjs/getting-started/quickstart)!
11-
128
<Steps>
13-
## Enable organizations in the Clerk Dashboard
9+
## Enable organizations
1410

1511
Organizations are disabled by default. To enable them:
1612

@@ -23,13 +19,11 @@ Organizations let you group users with roles and permissions, enabling you to bu
2319

2420
Learn more about configuring organizations in the [dedicated guide](/docs/guides/organizations/configure).
2521

26-
## Add the OrganizationSwitcher component
22+
## Add the `<OrganizationSwitcher />` component
2723

28-
The [`<OrganizationSwitcher />`](/docs/reference/components/organization/organization-switcher) component is the easiest way to let users create, switch between, and manage organizations. Add it to your app's header or navigation:
24+
The [`<OrganizationSwitcher />`](/docs/reference/components/organization/organization-switcher) component is the easiest way to let users create, switch between, and manage organizations. It's recommended to add it in your app's header or navigation so that it's always readily available to your users. For example:
2925

3026
```tsx {{ filename: 'components/Header.tsx' }}
31-
import { OrganizationSwitcher } from '@clerk/nextjs'
32-
3327
export default function Header() {
3428
return (
3529
<header>
@@ -39,126 +33,241 @@ Organizations let you group users with roles and permissions, enabling you to bu
3933
}
4034
```
4135

42-
The `<OrganizationSwitcher />` component handles all organization flows including:
43-
44-
- Creating new organizations
45-
- Switching between organizations
46-
- Managing the active organization's profile
47-
- Viewing organization members and invitations
48-
4936
## Access organization data
5037

51-
Use Clerk's hooks to access the current organization and role in your components:
52-
53-
```tsx {{ filename: 'app/page.tsx', mark: [3, [6, 9], 14, 17] }}
54-
'use client'
55-
56-
import { useOrganization, useOrganizationList } from '@clerk/nextjs'
57-
58-
export default function Home() {
59-
const { organization } = useOrganization()
60-
const { userMemberships } = useOrganizationList({
61-
userMemberships: true,
62-
})
63-
64-
return (
65-
<div className="p-8">
66-
<h1 className="text-2xl font-bold mb-4">
67-
Welcome to the <strong>{organization?.name}</strong> organization
68-
</h1>
69-
<p className="mb-6">
70-
Your role in this organization:{' '}
71-
<strong>
72-
{
73-
userMemberships?.data?.find(
74-
(membership) => membership.organization.id === organization?.id,
75-
)?.role
76-
}
77-
</strong>
78-
</p>
79-
</div>
80-
)
81-
}
82-
```
83-
84-
## Visit your app
85-
86-
Run your project with the following command:
87-
88-
```npm
89-
npm run dev
90-
```
91-
92-
Visit your app locally at [localhost:3000](http://localhost:3000).
93-
94-
## Create and switch organization
95-
96-
Use `<OrganizationSwitcher />` to create, switch between, and manage organizations.
97-
98-
1. Click on the `<OrganizationSwitcher />` component, then **Create an organization**.
99-
100-
1. Enter `Acme Org` as the organization name.
101-
102-
1. Invite users to your organization and select their role.
103-
104-
## Protect routes by organization and roles
105-
106-
You can protect routes based on organization membership, roles, and permissions. The `/protected` page checks if you are an admin in the `Acme Corp` organization:
107-
108-
```tsx {{ filename: 'app/protected/page.tsx', mark: [1, 6, 13, 14, 17, 18] }}
109-
import { auth, clerkClient } from '@clerk/nextjs/server'
110-
111-
export default async function Page() {
112-
// Protect the route by checking for a specific role
113-
// This will throw a 404 if the user is not authenticated or doesn't have the role
114-
const { orgId } = await auth.protect({ role: 'org:admin' })
115-
116-
if (!orgId) {
117-
return (
118-
<p className="text-red-600">
119-
You must be signed in as an <strong>admin</strong> to access this page.
120-
</p>
121-
)
122-
}
123-
124-
// Fetch the organization to check its name
125-
const client = await clerkClient()
126-
const organization = await client.organizations.getOrganization({ organizationId: orgId })
127-
128-
// Check if organization name matches (e.g., "Acme Corp")
129-
const requiredOrgName = 'Acme Corp'
130-
if (organization.name !== requiredOrgName) {
131-
return (
132-
<p className="text-red-600">
133-
You are currently not signed in as an <strong>admin</strong> in the{' '}
134-
<strong>{requiredOrgName}</strong> organization.
135-
</p>
136-
)
137-
}
138-
139-
return (
140-
<p className="text-green-600">
141-
You are currently signed in as an <strong>admin</strong> in the{' '}
142-
<strong>{requiredOrgName}</strong> organization.
143-
</p>
144-
)
145-
}
146-
```
147-
148-
Learn more about protecting routes and checking organization roles in the [authorization guide](/docs/guides/organizations/roles-and-permissions).
38+
<Tabs items={['Client-side', 'Server-side']}>
39+
<Tab>
40+
Use Clerk's [`useOrganization()`](/docs/reference/hooks/use-organization) hook to access information about the currently active organization. Use Clerk's [`useOrganizationList()`](/docs/reference/hooks/use-organization-list) hook to access information about the current user's organization memberships.
41+
42+
```tsx
43+
export default function Page() {
44+
const { organization } = useOrganization()
45+
const { userMemberships } = useOrganizationList({
46+
userMemberships: true,
47+
})
48+
49+
return (
50+
<div className="p-8">
51+
<h1 className="text-2xl font-bold mb-4">
52+
Welcome to the <strong>{organization?.name}</strong> organization
53+
</h1>
54+
<p className="mb-6">
55+
Your role in this organization:{' '}
56+
<strong>
57+
{/* Find the organization membership that matches the
58+
currently active organization and return the role */}
59+
{
60+
userMemberships?.data?.find(
61+
(membership) => membership.organization.id === organization?.id,
62+
)?.role
63+
}
64+
</strong>
65+
</p>
66+
</div>
67+
)
68+
}
69+
```
70+
</Tab>
71+
72+
<Tab>
73+
[Clerk's JS Backend SDK](/docs/js-backend/getting-started/quickstart) provides methods for accessing organization data server-side. For example, to get information about an organization, you can use the [`getOrganization()`](/docs/reference/backend/organization/get-organization) method. It requires the organization ID, which can be accessed through the [`Auth`](/docs/reference/backend/types/auth-object) object.
74+
75+
This example is written for Next.js App Router, but can be adapted to other frameworks by using the appropriate method for accessing the [`Auth` object](/docs/reference/backend/types/auth-object), and the appropriate initialization for `clerkClient()`.
76+
77+
```tsx
78+
import { auth, clerkClient } from '@clerk/nextjs/server'
79+
import { OrganizationSwitcher } from '@clerk/nextjs'
80+
81+
export default async function Page() {
82+
// The `Auth` object gives you access to properties like `orgId`
83+
// Accessing the `Auth` object differs depending on the SDK you're using
84+
// https://clerk.com/docs/reference/backend/types/auth-object#how-to-access-the-auth-object
85+
const { orgId } = await auth()
86+
87+
// Check if there is an active organization
88+
if (!orgId) {
89+
return (
90+
<>
91+
<p>Set an active organization to access this page.</p>
92+
<OrganizationSwitcher />
93+
</>
94+
)
95+
}
96+
97+
// To fetch the active organization server-side,
98+
// first initialize the JS Backend SDK.
99+
// This varies depending on the SDK you're using
100+
// https://clerk.com/docs/js-backend/getting-started/quickstart
101+
// Then use the `clerkClient()` to access the `getOrganization()` method
102+
const client = await clerkClient()
103+
const organization = await client.organizations.getOrganization({ organizationId: orgId })
104+
105+
return <p>Hello {organization.name}</p>
106+
}
107+
```
108+
</Tab>
109+
</Tabs>
110+
111+
## Protect content
112+
113+
<Tabs items={['Client-side', 'Server-side']}>
114+
<Tab>
115+
You can protect content and even entire routes based on organization membership, roles, and permissions by performing [authorization checks](!authorization-check).
116+
117+
In the following example, the page is protected from unauthenticated users, users that don't have the `org:admin` role, and users that are not in the `Acme Corp` organization.
118+
119+
- The [`Auth`](/docs/reference/backend/types/auth-object) object is used to access the `isSignedIn` and `has()` properties.
120+
- The `isSignedIn` property is used to check if the user is signed in.
121+
- The `has()` helper is used to check if the user has the `org:admin` role.
122+
- The [`useOrganization()`](/docs/reference/hooks/use-organization) hook is used to access the organization data.
123+
- The organization name is checked to ensure it matches the required organization name. If a user is not in the required organization, the page will display a message and the [`<OrganizationSwitcher />`](/docs/reference/components/organization/organization-switcher) component will be rendered to allow the user to switch to the required organization.
124+
125+
```tsx {{ filename: 'app/protected/page.tsx' }}
126+
'use client'
127+
import { OrganizationSwitcher, useAuth, useOrganization } from '@clerk/nextjs'
128+
129+
export default function Page() {
130+
// The `useAuth()` hook gives you access to properties like `isSignedIn` and `has()`
131+
const { isSignedIn, has } = useAuth()
132+
const { organization } = useOrganization()
133+
134+
// Check if the user is authenticated
135+
if (!isSignedIn) {
136+
return <p>You must be signed in to access this page.</p>
137+
}
138+
139+
// Check if there is an active organization
140+
if (!organization) {
141+
return (
142+
<>
143+
<p>Set an active organization to access this page.</p>
144+
<OrganizationSwitcher />
145+
</>
146+
)
147+
}
148+
149+
// Check if the user has the `org:admin` role
150+
if (!has({ role: 'org:admin' })) {
151+
return <p>You must be an admin to access this page.</p>
152+
}
153+
154+
// Check if organization name matches (e.g., "Acme Corp")
155+
const requiredOrgName = 'Acme Corp'
156+
if (organization.name !== requiredOrgName) {
157+
return (
158+
<>
159+
<p>
160+
This page is only accessible in the <strong>{requiredOrgName}</strong> organization.
161+
Switch to the <strong>{requiredOrgName}</strong> organization to access this page.
162+
</p>
163+
<OrganizationSwitcher />
164+
</>
165+
)
166+
}
167+
168+
return (
169+
<p>
170+
You are currently signed in as an <strong>admin</strong> in the{' '}
171+
<strong>{organization.name}</strong> organization.
172+
</p>
173+
)
174+
}
175+
```
176+
177+
For more examples on how to perform authorization checks, see the [dedicated guide](/docs/guides/secure/authorization-checks).
178+
</Tab>
179+
180+
<Tab>
181+
You can protect content and even entire routes based on organization membership, roles, and permissions by performing [authorization checks](!authorization-check).
182+
183+
In the following example, the page is protected from unauthenticated users, users that don't have the `org:admin` role, and users that are not in the `Acme Corp` organization.
184+
185+
- The [`Auth`](/docs/reference/backend/types/auth-object) object is used to access the `isAuthenticated`, `orgId`, and `has()` properties.
186+
- The `isAuthenticated` property is used to check if the user is authenticated.
187+
- The `orgId` property is used to check if there is an [active organization](!active-organization).
188+
- The `has()` helper is used to check if the user has the `org:admin` role.
189+
- To fetch the organization server-side, the [`clerkClient()`](/docs/reference/nextjs/overview#clerk-client) helper is used to access the [`getOrganization()`](/docs/reference/backend/organization/get-organization) method.
190+
- The organization name is checked to ensure it matches the required organization name. If a user is not in the required organization, the page will display a message and the [`<OrganizationSwitcher />`](/docs/reference/components/organization/organization-switcher) component will be rendered to allow the user to switch to the required organization.
191+
192+
This example is written for Next.js App Router, but can be adapted to other frameworks by using the appropriate method for accessing the [`Auth` object](/docs/reference/backend/types/auth-object).
193+
194+
```tsx {{ filename: 'app/protected/page.tsx' }}
195+
import { auth, clerkClient } from '@clerk/nextjs/server'
196+
import { OrganizationSwitcher } from '@clerk/nextjs'
197+
198+
export default async function Page() {
199+
// The `Auth` object gives you access to properties like `isAuthenticated` and `userId`
200+
// Accessing the `Auth` object differs depending on the SDK you're using
201+
// https://clerk.com/docs/reference/backend/types/auth-object#how-to-access-the-auth-object
202+
const { isAuthenticated, orgId, has } = await auth()
203+
204+
// Check if the user is authenticated
205+
if (!isAuthenticated) {
206+
return <p>You must be signed in to access this page.</p>
207+
}
208+
209+
// Check if there is an active organization
210+
if (!orgId) {
211+
return (
212+
<>
213+
<p>Set an active organization to access this page.</p>
214+
<OrganizationSwitcher />
215+
</>
216+
)
217+
}
218+
219+
// Check if the user has the `org:admin` role
220+
if (!has({ role: 'org:admin' })) {
221+
return <p>You must be an admin to access this page.</p>
222+
}
223+
224+
// To fetch the active organization server-side,
225+
// first initialize the JS Backend SDK.
226+
// This varies depending on the SDK you're using
227+
// https://clerk.com/docs/js-backend/getting-started/quickstart
228+
// Then use the `clerkClient()` to access the `getOrganization()` method
229+
const client = await clerkClient()
230+
const organization = await client.organizations.getOrganization({ organizationId: orgId })
231+
232+
// Check if organization name matches (e.g., "Acme Corp")
233+
const requiredOrgName = 'Acme Corp'
234+
if (organization.name !== requiredOrgName) {
235+
return (
236+
<>
237+
<p>
238+
This page is only accessible in the <strong>{requiredOrgName}</strong> organization.
239+
Switch to the <strong>{requiredOrgName}</strong> organization to access this page.
240+
</p>
241+
<OrganizationSwitcher />
242+
</>
243+
)
244+
}
245+
246+
return (
247+
<p>
248+
You are currently signed in as an <strong>admin</strong> in the{' '}
249+
<strong>{organization.name}</strong> organization.
250+
</p>
251+
)
252+
}
253+
```
254+
255+
For more examples on how to perform authorization checks, see the [dedicated guide](/docs/guides/secure/authorization-checks).
256+
</Tab>
257+
</Tabs>
149258

150259
## It's time to build your B2B SaaS!
151260

152261
You've added Clerk organizations to your Next.js app 🎉. Ready to scale to enterprise customers?
153262

154-
- **Control access** with [custom roles and permissions](/docs/guides/organizations/roles-and-permissions) define granular permissions for different user types within organizations.
263+
- **Control access** with [custom roles and permissions](/docs/guides/organizations/roles-and-permissions): define granular permissions for different user types within organizations.
155264

156-
- **Onboard entire companies** with [verified domains](/docs/guides/organizations/verified-domains) automatically invite users with approved email domains (e.g., `@company.com`) to join organizations without manual invitations.
265+
- **Onboard entire companies** with [verified domains](/docs/guides/organizations/verified-domains): automatically invite users with approved email domains (e.g., `@company.com`) to join organizations without manual invitations.
157266

158-
- **Enable enterprise SSO** with [SAML and OIDC](/docs/guides/organizations/sso) let customers authenticate through their identity provider (Okta, Entra ID, Google Workspace) with unlimited connections, no per-connection fees.
267+
- **Enable enterprise SSO** with [SAML and OIDC](/docs/guides/organizations/sso): let customers authenticate through their identity provider (Okta, Entra ID, Google Workspace) with unlimited connections, no per-connection fees.
159268
</Steps>
160269

161-
## Next steps
270+
## Additional resources
162271

163272
<Cards>
164273
- [Create and manage organizations](/docs/guides/organizations/create-and-manage)

0 commit comments

Comments
 (0)