Skip to content

Commit

Permalink
done?
Browse files Browse the repository at this point in the history
  • Loading branch information
alexisintech committed Dec 20, 2024
1 parent beb0054 commit d3ff29f
Show file tree
Hide file tree
Showing 13 changed files with 85 additions and 93 deletions.
2 changes: 2 additions & 0 deletions docs/_partials/has-warning.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
> [!WARNING]
> When using `has()` **on the server-side** to check permissions, it only works with **custom permissions**, as [system permissions](/docs/organizations/roles-permissions#system-permissions) are not included in `auth.sessionClaims.orgs_permissions`. To check system permissions, verify the user's role instead.
2 changes: 1 addition & 1 deletion docs/customization/user-button.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@ With the above example, the `<UserButton />` menu items will be in the following

## Conditionally render menu items

To conditionally render menu items based on a user's role or permissions, you can use the [`has()`](/docs/references/backend/types/auth-object#has) helper function:
To conditionally render menu items based on a user's role or custom permissions, you can use the [`has()`](/docs/references/backend/types/auth-object#has) helper function:

<Tabs items={["Next.js", "Astro"]}>
<Tab>
Expand Down
4 changes: 2 additions & 2 deletions docs/organizations/roles-permissions.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ Permissions grant users privileged access to resources and operations, like crea

Clerk has a set of system permissions that power [Clerk's Frontend API](/docs/reference/frontend-api){{ target: '_blank' }} and [organization-related Clerk components](/docs/components/overview#organization-components). They are a baseline set of permissions that Clerk needs to operate functionally.

Clerks system permissions consist of the following:
Clerk's system permissions consist of the following:

- Manage Organization (`org:sys_profile:manage`)
- Delete Organization (`org:sys_profile:delete`)
Expand All @@ -61,7 +61,7 @@ Clerk’s system permissions consist of the following:
You can assign these system permissions to any role.

> [!WARNING]
> System permissions are not included in session claims. To do permission-checks on the server-side, you must [create custom permissions](/docs/organizations/create-roles-permissions).
> System permissions are not included in [session claims](/docs/backend-requests/resources/session-tokens#default-session-claims). To do permission-checks on the server-side, you must [create custom permissions](/docs/organizations/create-roles-permissions).
### Custom permissions

Expand Down
2 changes: 1 addition & 1 deletion docs/organizations/verified-domains.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Once a domain is added and verified in your organization, the user will have the

## Adding and verifying domains

Domains can be added and verified under an organization by any user with the `org:sys_domains:manage` permission. By default, admins have this permission. The easiest way to add and verify domains is by using Clerk's \[`<OrganizationSwitcher />`] component. In the **General** tab, there will be a **Verified domains** section.
Domains can be added and verified under an organization by any user with the `org:sys_domains:manage` permission. By default, admins have this permission. The easiest way to add and verify domains is by using Clerk's [`<OrganizationSwitcher />`](/docs/components/organization/organization-switcher) component. In the **General** tab, there will be a **Verified domains** section.

Domains can be verified through an email verification code sent to an email that matches the domain. If the user adding the domain already has a verified email using that domain in their account, the domain will be automatically verified.

Expand Down
6 changes: 3 additions & 3 deletions docs/references/astro/clerk-middleware.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export const onRequest = clerkMiddleware((auth, context) => {

### Protect routes based on user authorization status

To protect routes based on user authorization status, use [`auth().has()`](/docs/references/backend/types/auth-object#has){{ target: '_blank' }} to check if the user has the required roles or permissions.
To protect routes based on user authorization status, use [`auth().has()`](/docs/references/backend/types/auth-object#has){{ target: '_blank' }} to check if the user has the required roles or custom permissions.

```tsx {{ filename: 'src/middleware.ts' }}
import { clerkMiddleware, createRouteMatcher } from '@clerk/astro/server'
Expand All @@ -68,8 +68,8 @@ export const onRequest = clerkMiddleware((auth, context) => {

// Restrict admin routes to users with specific permissions
if (
(isProtectedRoute(context.request) && !has({ permission: 'org:sys_memberships:manage' })) ||
!has({ permission: 'org:sys_domains_manage' })
(isProtectedRoute(context.request) && !has({ permission: 'org:admin:example1' })) ||
!has({ permission: 'org:admin:example2' })
) {
// Add logic to run if the user does not have the required permissions; for example, redirecting to the sign-in page
return redirectToSignIn()
Expand Down
13 changes: 6 additions & 7 deletions docs/references/backend/types/auth-object.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ The `Auth` object is available on the `request` object in server contexts. Some
- [`has()`](#has)
- <code>(isAuthorizedParams: [CheckAuthorizationParamsWithCustomPermissions](#check-authorization-params-with-custom-permissions)) => boolean</code>

A function that returns a boolean based on the permission or role provided as parameter. Can be used for authorization.
A function that checks if the user has an organization role or custom permission.

---

Expand All @@ -96,7 +96,7 @@ The `Auth` object is available on the `request` object in server contexts. Some
- [`getToken()`](#get-token)
- [`ServerGetToken`](#server-get-token)

A function that returns a promise that resolves to the current user's session token. Can also be used to retrieve a custom JWT template.
A function that gets the current user's [session token](/docs/backend-requests/resources/session-tokens) or a [custom JWT template](/docs/backend-requests/making/jwt-templates).

---

Expand Down Expand Up @@ -208,16 +208,15 @@ The `ReverificationConfig` type has the following properties:

You can use `has()` to check if a user is authorized to access a component.

> [!WARNING]
> When using `has()` on the **server-side**, it checks the `orgs_permissions` property in the user's `auth.sessionClaims`. [**System** permissions](/docs/organizations/roles-permissions#system-permissions) aren't included in session claims and therefore, can't be used to perform authorization checks. **You must use custom permissions instead**.
<Include src="_partials/has-warning" />

In the following example, `has()` is used to check if the user has the `org:team_settings:manage` permission. If the user does not have the permission, `null` is returned and the page is not rendered.
In the following example, `has()` is used to check if the user has the `org:team_settings:manage` permission. If the user does not have the permission, `null` is returned and the page is not rendered. This example is written for Next.js App Router, but it can be adapted to other frameworks by using the appropriate method for accessing the `Auth` object.

```tsx {{ filename: 'app/page.tsx' }}
import { auth } from '@clerk/nextjs/server'
export default async function Page() {
const { has } = await auth() // Accessing the `auth` object will depend on the framework you're using
const { has } = await auth()
const canManage = has({ permission: 'org:team_settings:manage' })
Expand All @@ -238,7 +237,7 @@ You can use `has()` to check if a user has verified their credentials within a c

### `getToken()`

`getToken()` retrieves the user's session token or a [custom JWT template](/docs/backend-requests/making/jwt-templates). It has the following signature:
`getToken()` retrieves the current user's [session token](/docs/backend-requests/resources/session-tokens) or a [custom JWT template](/docs/backend-requests/making/jwt-templates).

```typescript
const getToken: ServerGetToken
Expand Down
2 changes: 1 addition & 1 deletion docs/references/express/overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ const hasPermission = (req, res, next) => {
const auth = getAuth(req)

// Handle if the user is not authorized
if (!auth.has({ permission: 'org:admin:testpermission' })) {
if (!auth.has({ permission: 'org:admin:example' })) {
return res.status(403).send('Forbidden')
}

Expand Down
2 changes: 1 addition & 1 deletion docs/references/ios/get-token.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ title: '`getToken()`'
description: Use Clerk's iOS SDK to retrieve a token for a JWT template that is defined in the Clerk Dashboard.
---

Retrieves the user's session token for the [default Clerk token](/docs/backend-requests/resources/session-tokens) or the given [JWT template](/docs/backend-requests/making/jwt-templates).
Retrieves the user's [session token](/docs/backend-requests/resources/session-tokens) or a [custom JWT template](/docs/backend-requests/making/jwt-templates).

This method uses a cache so a network request will only be made if the token in memory has expired. The TTL for a Clerk token is one minute.

Expand Down
2 changes: 1 addition & 1 deletion docs/references/javascript/session.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ function touch(): Promise<Session>

### `getToken()`

Retrieves the user's session token for the default Clerk token or the given template.
Retrieves the current user's [session token](/docs/backend-requests/resources/session-tokens) or a [custom JWT template](/docs/backend-requests/making/jwt-templates).

This method uses a cache so a network request will only be made if the token in memory has expired. The TTL for a Clerk token is one minute.

Expand Down
16 changes: 10 additions & 6 deletions docs/references/nextjs/auth.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ The following table describes how `auth.protect()` behaves based on user authent
- `has?`
- `(isAuthorizedParams: CheckAuthorizationParamsWithCustomPermissions) => boolean`

A function that returns a boolean based on the permission or role provided as parameter. Can be used for authorization. See [the dedicated `has()` section](/docs/references/backend/types/auth-object#has) for more information.
A function that checks if the user has an organization role or custom permission. See the [reference](/docs/references/backend/types/auth-object#has) for more information.

---

Expand Down Expand Up @@ -100,7 +100,7 @@ export default async function Page() {
}
```

## Use `auth()` to retrieve `userId`
## Use `auth()` to protect pages

You can use `auth()` to check if a `userId` exists. If it does not, that means there is no user signed in. You can use this information to protect pages, as shown in the following example:

Expand All @@ -116,6 +116,14 @@ export default async function Page() {
}
```

## Use `auth()` in API routes

See detailed examples in the [dedicated guide](/docs/references/nextjs/read-session-data).

## Use `auth()` to check roles and permissions

You can use `auth()` to check if a user is authorized to access certain parts of your application or even entire routes. See detailed examples in the [dedicated guide](/docs/organizations/verify-user-permissions).

## Use `auth()` for data fetching

When using a Clerk integration, or if you need to send a JWT along to a server, you can use the `getToken()` function that is returned by `auth()`.
Expand Down Expand Up @@ -143,7 +151,3 @@ export async function GET() {
}
}
```

## Use `auth()` to protect your app

You can protect certain parts of your application or even entire routes based on a user's authentication and/or authorization status. See detailed examples in the [dedicated guide](/docs/organizations/verify-user-permissions).
101 changes: 52 additions & 49 deletions docs/references/nextjs/clerk-middleware.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -112,59 +112,65 @@ There are two methods that you can use:
- Use [`auth.protect()`](/docs/references/nextjs/auth#protect) if you want Clerk to return a `404` if the user does not have the role or permission.
- Use [`auth().has()`](/docs/references/backend/types/auth-object#has) if you want more control over what your app does based on the authorization status.

<CodeBlockTabs options={["auth.protect()", "auth().has()"]}>
```tsx {{ filename: 'middleware.ts' }}
import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server'

const isProtectedRoute = createRouteMatcher(['/admin(.*)'])
<Tabs items={["auth.protect()", "auth().has()"]}>
<Tab>
```tsx {{ filename: 'middleware.ts' }}
import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server'

const isProtectedRoute = createRouteMatcher(['/admin(.*)'])

export default clerkMiddleware(async (auth, req) => {
// Restrict admin routes to users with specific permissions
if (isProtectedRoute(req)) {
await auth.protect((has) => {
return has({ permission: 'org:admin:example1' }) || has({ permission: 'org:admin:example2' })
})
}
})

export default clerkMiddleware(async (auth, req) => {
// Restrict admin routes to users with specific permissions
if (isProtectedRoute(req)) {
await auth.protect((has) => {
return has({ permission: 'org:admin:example1' }) || has({ permission: 'org:admin:example2' })
})
export const config = {
matcher: [
// Skip Next.js internals and all static files, unless found in search params
'/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)',
// Always run for API routes
'/(api|trpc)(.*)',
],
}
})
```
</Tab>

export const config = {
matcher: [
// Skip Next.js internals and all static files, unless found in search params
'/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)',
// Always run for API routes
'/(api|trpc)(.*)',
],
}
```
<Tab>
<Include src="_partials/has-warning" />

```tsx {{ filename: 'middleware.ts' }}
import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server'
```tsx {{ filename: 'middleware.ts' }}
import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server'

const isProtectedRoute = createRouteMatcher(['/admin(.*)'])
const isProtectedRoute = createRouteMatcher(['/admin(.*)'])

export default clerkMiddleware(async (auth, req) => {
const { has, redirectToSignIn } = await auth()
// Restrict admin routes to users with specific permissions
if (
(isProtectedRoute(req) && !has({ permission: 'org:sys_memberships:manage' })) ||
!has({ permission: 'org:sys_domains_manage' })
) {
// Add logic to run if the user does not have the required permissions
export default clerkMiddleware(async (auth, req) => {
const { has, redirectToSignIn } = await auth()
// Restrict admin routes to users with specific permissions
if (
(isProtectedRoute(req) && !has({ permission: 'org:admin:example1' })) ||
!has({ permission: 'org:admin:example2' })
) {
// Add logic to run if the user does not have the required permissions

return redirectToSignIn()
}
})
return redirectToSignIn()
}
})

export const config = {
matcher: [
// Skip Next.js internals and all static files, unless found in search params
'/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)',
// Always run for API routes
'/(api|trpc)(.*)',
],
}
```
</CodeBlockTabs>
export const config = {
matcher: [
// Skip Next.js internals and all static files, unless found in search params
'/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)',
// Always run for API routes
'/(api|trpc)(.*)',
],
}
```
</Tab>
</Tabs>

## Protect multiple groups of routes

Expand All @@ -183,10 +189,7 @@ export default clerkMiddleware(async (auth, req) => {
// Restrict admin routes to users with specific permissions
if (isTenantAdminRoute(req)) {
await auth.protect((has) => {
return (
has({ permission: 'org:sys_memberships:manage' }) ||
has({ permission: 'org:sys_domains_manage' })
)
return has({ permission: 'org:admin:example1' }) || has({ permission: 'org:admin:example2' })
})
}
// Restrict organization routes to signed in users
Expand Down
25 changes: 4 additions & 21 deletions docs/references/nextjs/get-auth.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -26,30 +26,13 @@ The `getAuth()` helper retrieves authentication state from the request object.

## Returns

`getAuth()` returns the [`Auth`](/docs/references/backend/types/auth-object) object.
`getAuth()` returns the `Auth` object. See the [`Auth` reference](/docs/references/backend/types/auth-object) for more information.

## Usage

### Basic usage

The following example demonstrates how to use `getAuth()` to retrieve authentication information in an API route.

```tsx {{ filename: 'app/api/example/route.ts' }}
import { getAuth } from '@clerk/nextjs/server'
import type { NextApiRequest, NextApiResponse } from 'next'

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const { userId } = getAuth(req)

// Add logic that retrieves the data for the API route

return res.status(200).json({ userId: userId })
}
```

### Protect API routes

It is important to protect your API routes to ensure that only authenticated users can access them. You can do this by checking if the `userId` is present in the `getAuth()` response, like in the following example:
The following example demonstrates how to protect an API route by checking if the `userId` is present in the `getAuth()` response.

```tsx {{ filename: 'app/api/example/route.ts' }}
import { getAuth } from '@clerk/nextjs/server'
Expand All @@ -70,7 +53,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)

### Usage with `getToken()`

`getAuth()` returns `getToken()`, which is a method that returns the current user's session token. You can also use this function to retrieve a custom JWT template, like in the following example:
`getAuth()` returns [`getToken()`](/docs/references/backend/types/auth-object#get-token), which is a method that returns the current user's session token or a custom JWT template.

```tsx {{ filename: 'app/api/example/route.ts' }}
import { getAuth } from '@clerk/nextjs/server'
Expand All @@ -90,7 +73,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)

### Usage with `clerkClient`

`clerkClient` is used to access the [Backend SDK](/docs/references/backend/overview), which exposes Clerk's Backend API resources. You can use `getAuth()` to pass authentication information that many of the Backend SDK methods require, like in the following example:
`clerkClient` is used to access the [Backend SDK](/docs/references/backend/overview), which exposes Clerk's Backend API resources. You can use `getAuth()` to pass authentication information that many of the Backend SDK methods require, like the user's ID.

```tsx {{ filename: 'app/api/example/route.ts' }}
import { clerkClient, getAuth } from '@clerk/nextjs/server'
Expand Down
1 change: 1 addition & 0 deletions docs/references/nextjs/read-session-data.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ Under the hood, `currentUser()` uses the [`clerkClient`](/docs/references/backen
// Get the userId from auth() -- if null, the user is not signed in
const { userId } = await auth()

// Protect the route by checking if the user is signed in
if (!userId) {
return new NextResponse('Unauthorized', { status: 401 })
}
Expand Down

0 comments on commit d3ff29f

Please sign in to comment.