Skip to main content
Docs

Check roles and permissions with authorization checks

Authorization checks verify that users can only access resources and perform actions they have permission for within an organization. These checks are essential for protecting sensitive data, gating premium features, and ensuring users stay within their allowed scope of access.

Clerk provides two primary ways to perform these checks: the has() method for server-side logic and the <Protect> component for conditional rendering in React. Both methods let you check against roles, permissions, features, and plans.

What you can check

Authorization checks can verify roles and custom permissions. Roles like org:admin determine a user's level of access within an organization, while custom permissions like org:invoices:create provide fine-grained control over specific features and actions.

Important

Clerk links custom permissions to features. A permission check for org:invoices:create will only return true if the organization's active plan includes the invoices feature and the user has the permission. Learn more in the roles and permissions guide.

Frontend checks with <Protect>

The <Protect> component is the easiest way to conditionally show or hide content in React applications based on what a user can access. This works well for UI elements like buttons, sections, or entire page layouts that should only appear to users with specific access. You can show or hide content based on roles and permissions, render different layouts for different access levels, or display fallback messages when access is denied.

Use the <Protect> component to conditionally render content based on role or permission:

import { Protect } from '@clerk/nextjs'

export default function Dashboard() {
  return (
    <div>
      <h1>Dashboard</h1>

      {/* Only show to org admins */}
      <Protect role="org:admin">
        <AdminSettings />
      </Protect>

      {/* Only show to users with specific permission */}
      <Protect permission="org:invoices:create">
        <CreateInvoiceButton />
      </Protect>

      {/* Display fallback when access is denied */}
      <Protect permission="org:reports:read" fallback={<p>You don't have access to reports.</p>}>
        <ReportsSection />
      </Protect>
    </div>
  )
}

Server-side checks with has()

While <Protect> works well for the frontend, server-side checks are essential for securing API routes, backend logic, and data access. The has() method provides a way to verify access before performing sensitive operations or returning protected data. You'll use this when protecting API endpoints, controlling database operations, validating permissions before executing business logic, or returning different data based on user access.

Use the has() method from the auth() object to check permissions on the server:

import { auth } from '@clerk/nextjs/server'

export default async function handler(req, res) {
  const { has, userId } = await auth()

  if (!userId) {
    return res.status(401).json({ error: 'Unauthorized' })
  }

  // Check if user has admin role
  if (!has({ role: 'org:admin' })) {
    return res.status(403).json({ error: 'Forbidden' })
  }

  // Check if user has specific permission
  if (!has({ permission: 'org:invoices:create' })) {
    return res.status(403).json({ error: 'Forbidden' })
  }

  // Proceed with authorized action
  // ...
}

Next steps

Now that you know how to check roles and permissions, you can:

Feedback

What did you think of this content?

Last updated on