Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions docs/billing/b2b-saas.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Clerk billing for B2B SaaS allows you to create plans and manage subscriptions *

## Create a plan

Subscription plans are what your customers subscribe to. There is no limit to the number of plans you can create.
Subscription plans are what your customers subscribe to. There is no limit to the number of plans you can create. If your Clerk instance has existing custom permissions, the corresponding features from those permissions will automatically be added to the free plan for orgs. This ensures that organization members get the same set of custom permissions when billing is enabled, because all organizations start on the free plan.

To create a plan, navigate to the [**Plans**](https://dashboard.clerk.com/last-active?path=billing/plans) page in the Clerk Dashboard. Here, you can create, edit, and delete plans. To setup B2B billing, select the **Plans for Organizations** tab and select **Add Plan**. When creating a plan, you can also create features for the plan; see the next section for more information.

Expand Down Expand Up @@ -55,7 +55,9 @@ export default function Page() {

## Control access with features, plans, and permissions

You can use Clerk's features, plans, and permissions to gate access to the content. There are a few ways to do this, but the recommended and simplest way is either using the [`has()`](/docs/references/backend/types/auth-object#has) method or the [`<Protect>`](/docs/components/protect) component.
You can use Clerk's features, plans, and permissions to gate access to content using [**authorization checks**](/docs/guides/authorization-checks). There are a few ways to do this, but the recommended and simplest way is either using the [`has()`](/docs/references/backend/types/auth-object#has) method or the [`<Protect>`](/docs/components/protect) component.

Permission-based authorization checks link with feature-based authorization checks. This means that if you are checking a custom permission, it will only work if the feature part of the permission key (`org:<feature>:<action>`) **is a feature included in the organization's active plan**. For example, say you want to check if an organization member has the custom permission `org:teams:manage`, where `teams` is the feature. Before performing the authorization check, you need to ensure that the user's organization is subscribed to a plan that has the `teams` feature. If the user's organization is not subscribed to a plan that has the `teams` feature, the authorization check will always return `false`, even if the user has the custom permission.

The `has()` method is available for any JavaScript framework, while `<Protect>` is only available for React-based frameworks.

Expand All @@ -77,6 +79,15 @@ const hasPremiumAccess = has({ feature: 'widgets' })

The [`has()`](/docs/references/backend/types/auth-object#has) method checks if the organization has been granted a specific type of access control (role, permission, feature, or plan) and returns a boolean value. It is available on the [`auth` object](/docs/references/backend/types/auth-object) on the server. Depending on the framework you are using, you will access the `auth` object differently.

> [!TIP]
> Why aren't custom permissions appearing in the session token (JWT) or in API responses (including the result of the `has()` check)?
>
> ---
>
> Custom permissions will only appear in the session token (JWT) and in API responses (including the result of the `has()` check) if the feature part of the permission key (`org:<feature>:<action>`) **is a feature included in the organization's active plan**. If the feature is not part of the plan, the `has()` check for permissions using that feature will return `false`, and those permissions will not be represented in the session token.
>
> For example, say you want to check if an organization member has the custom permission `org:teams:manage`, where `teams` is the feature. The user's organization must be subscribed to a plan that has the `teams` feature for authorization checks to work. If the user's organization is not subscribed to a plan that has the `teams` feature, the authorization check will always return `false`, even if the user has the custom permission.

The following example accesses the `auth` object and the `has()` method using the [Next.js-specific `auth()` helper](/docs/references/nextjs/auth).

<Tabs items={[ "Plan", "Feature", "Permission"]}>
Expand Down
1 change: 1 addition & 0 deletions docs/guides/authorization-checks.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ This guide will show you how to implement authorization checks in order to prote
- Note: Using `has()` **on the server-side** to check permissions works only with **custom permissions**, as [system permissions](/docs/organizations/roles-permissions#system-permissions) aren't included in the session token claims. To check system permissions, verify the user's role instead.
- Checking for a role or permission depends on the user having an [active organization](/docs/organizations/overview#active-organization). Without an active organization, the authorization checks will likely always evaluate to false by default.
- If you would like to perform role-based authorization checks **without** using Clerk's organizations feature, see [the Role Based Access Control (RBAC) guide](/docs/references/nextjs/basic-rbac).
- Permission-based authorization checks link with feature-based authorization checks. This means that if you are checking a custom permission, it will only work if the feature part of the permission key (`org:<feature>:<action>`) **is a feature included in the organization's active plan**. For example, say you want to check if an organization member has the custom permission `org:teams:manage`, where `teams` is the feature. Before performing the authorization check, you need to ensure that the user's organization is subscribed to a plan that has the `teams` feature. If the user's organization is not subscribed to a plan that has the `teams` feature, the authorization check will always return `false`, even if the user has the custom permission.

<If sdk="nextjs">
* Be cautious when doing authorization checks in layouts, as these don't re-render on navigation, meaning the user session won't be checked on every route change. [Read more in the Next.js docs](https://nextjs.org/docs/app/building-your-application/authentication#layouts-and-auth-checks).
Expand Down
10 changes: 2 additions & 8 deletions docs/references/backend/types/auth-object.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,8 @@ The `Auth` object contains important information like the current user's session

The `has()` helper can be used to do two types of checks:

- **Authorization:** Check if the user has been granted a specific type of access control (role, permission, feature, or plan) and returns a boolean value.
- **Reverification:** Check if the user has verified their credentials within a certain time frame and returns a boolean value.
- **Authorization:** Check if the user has been granted a specific type of access control (role, permission, feature, or plan) and returns a boolean value. For examples, see the [guide on verifying if a user is authorized](/docs/guides/authorization-checks).
- **Reverification:** Check if the user has verified their credentials within a certain time frame and returns a boolean value. For examples, see the [guide on reverification](/docs/guides/reverification).

```ts
function has(isAuthorizedParams: CheckAuthorizationParamsWithCustomPermissions): boolean
Expand Down Expand Up @@ -198,12 +198,6 @@ The `ReverificationConfig` type has the following properties:
The age of the factor level to check for. Value should be greater than or equal to 1 and less than 99,999.
</Properties>

#### Examples

**Authorization:** For examples of how to use `has()` to check if a user has been granted a specific type of access control (role, permission, feature, or plan), see the [guide on verifying if a user is authorized](/docs/guides/authorization-checks).

**Reverification:** For examples of how to use `has()` to check if a user has verified their credentials within a certain time frame, see the [guide on reverification](/docs/guides/reverification).

### `getToken()`

`getToken()` retrieves the current user's [session token](/docs/backend-requests/resources/session-tokens) or a [custom JWT template](/docs/backend-requests/jwt-templates).
Expand Down