Skip to main content
Docs

<Protect>

The <Protect> component protects content or even entire routes by checking if the user has been granted a specific type of access control (role, permission, feature, or plan). You can pass it a fallback prop that will be rendered if the user does not have the access control.

<Protect> can be used both client-side and server-side (in Server Components).

Caution

This component only visually hides its children when the current user is not authorized. The contents of its children remain accessible via the browser's source code even if the user fails the authorization check. Do not use this component to hide sensitive information that should be completely inaccessible to unauthorized users. For truly sensitive data, perform authorization checks on the server before sending the data to the client.

  • Name
    condition?
    Type
    has => boolean
    Description

    Optional conditional logic that renders the children if it returns true.

  • Name
    fallback?
    Type
    JSX
    Description

    Optional UI to show when a user doesn't have the correct type of access control to access the protected content.

  • Name
    feature?
    Type
    string
    Description

    Optional string corresponding to a feature.

  • Name
    plan?
    Type
    string
    Description

    Optional string corresponding to a plan.

  • Name
    permission?
    Type
    string
    Description

    Optional string corresponding to a permission in the format org:<resource>:<action>

  • Name
    role?
    Type
    string
    Description

    Optional string corresponding to a role in the format org:<role>

  • Name
    treatPendingAsSignedOut?
    Type
    boolean
    Description

    A boolean that indicates whether to treat pending sessions as signed out. Defaults to false.

Usage

To limit who is able to see the content that <Protect> renders, you can pass one of the access control props: permission, role, feature, or plan. It's recommended to use permission-based authorization over role-based authorization, and feature-based authorization over plan-based authorization, as they are more flexible, easier to manage, and more secure.

If you do not pass any of the access control props, <Protect> will render its children if the user is signed in, regardless of their role or its permissions.

For more complex authorization logic, pass conditional logic to the condition prop.

Render content by permissions

The following example demonstrates how to use the <Protect /> component to protect content by checking if the user has the org:invoices:create permission.

app/protected/invoices/page.tsx
import { Protect } from '@clerk/nextjs'

export default function Page() {
  return (
    <Protect
      permission="org:invoices:create"
      fallback={<p>You do not have the permissions to create an invoice.</p>}
    >
      <p>Users with permission org:invoices:create can see this.</p>
    </Protect>
  )
}
src/invoices.tsx
import { Protect } from '@clerk/clerk-react'

export default function Page() {
  return (
    <Protect
      permission="org:invoices:create"
      fallback={<p>You do not have the permissions to create an invoice.</p>}
    >
      <p>Users with permission org:invoices:create can see this.</p>
    </Protect>
  )
}
src/pages/invoices.astro
---
import { Protect } from '@clerk/astro/components'
---

<Protect permission="org:invoices:create">
  <p slot="fallback">You do not have the permissions to create an invoice.</p>
  <p>Users with permission org:invoices:create can see this.</p>
</Protect>
import { Protect } from '@clerk/clerk-expo'
import { Text } from 'react-native'

export default function Screen() {
  return (
    <Protect
      permission="org:invoices:create"
      fallback={<Text>You do not have the permissions to create an invoice.</Text>}
    >
      <Text>Users with permission org:invoices:create can see this.</Text>
    </Protect>
  )
}
app/routes/invoices.tsx
import { Protect } from '@clerk/react-router'

export default function InvoicesPage() {
  return (
    <Protect
      permission="org:invoices:create"
      fallback={<p>You do not have the permissions to create an invoice.</p>}
    >
      <p>Users with permission org:invoices:create can see this.</p>
    </Protect>
  )
}
app/routes/invoices.tsx
import { Protect } from '@clerk/tanstack-react-start'
import { createFileRoute } from '@tanstack/react-router'

export const Route = createFileRoute('/invoices')({
  component: InvoicesPage,
})

function InvoicesPage() {
  return (
    <Protect
      permission="org:invoices:create"
      fallback={<p>You do not have the permissions to create an invoice.</p>}
    >
      <p>Users with permission org:invoices:create can see this.</p>
    </Protect>
  )
}
<script setup lang="ts">
import { Protect } from '@clerk/vue'
</script>

<template>
  <Protect permission="org:invoices:create">
    <template #fallback>
      <p>You do not have the permissions to create an invoice.</p>
    </template>
    <p>Users with permission org:invoices:create can see this.</p>
  </Protect>
</template>

Render content by role

While authorization by permission is recommended, for convenience, <Protect> allows a role prop to be passed.

The following example demonstrates how to use the <Protect /> component to protect content by checking if the user has the org:billing role.

app/protected/billing/page.tsx
import { Protect } from '@clerk/nextjs'

export default function ProtectPage() {
  return (
    <Protect
      role="org:billing"
      fallback={<p>Only a member of the Billing department can access this content.</p>}
    >
      <p>Users with role org:billing can see this.</p>
    </Protect>
  )
}
src/billing.tsx
import { Protect } from '@clerk/clerk-react'

export default function Page() {
  return (
    <Protect
      role="org:billing"
      fallback={<p>Only a member of the Billing department can access this content.</p>}
    >
      <p>Users with role org:billing can see this.</p>
    </Protect>
  )
}
src/pages/billing.astro
---
import { Protect } from '@clerk/astro/components'
---

<Protect role="org:billing">
  <p slot="fallback">Only a member of the Billing department can access this content.</p>
  <p>Users with role org:billing can see this.</p>
</Protect>
import { Protect } from '@clerk/clerk-expo'
import { Text } from 'react-native'

export default function Screen() {
  return (
    <Protect
      permission="org:billing"
      fallback={<Text>Only a member of the Billing department can access this content.</Text>}
    >
      <Text>Users with role org:billing can see this.</Text>
    </Protect>
  )
}
app/routes/billing.tsx
import { Protect } from '@clerk/react-router'

export default function BillingPage() {
  return (
    <Protect
      role="org:billing"
      fallback={<p>Only a member of the Billing department can access this content.</p>}
    >
      <p>Users with role org:billing can see this.</p>
    </Protect>
  )
}
app/routes/billing.tsx
import { Protect } from '@clerk/tanstack-react-start'
import { createFileRoute } from '@tanstack/react-router'

export const Route = createFileRoute('/billing')({
  component: BillingPage,
})

function BillingPage() {
  return (
    <Protect
      role="org:billing"
      fallback={<p>Only a member of the Billing department can access this content.</p>}
    >
      <p>Users with role org:billing can see this.</p>
    </Protect>
  )
}
<script setup lang="ts">
import { Protect } from '@clerk/vue'
</script>

<template>
  <Protect role="org:billing">
    <template #fallback>
      <p>Only a member of the Billing department can access this content.</p>
    </template>
    <p>Users with role org:billing can see this.</p>
  </Protect>
</template>

Render content by plan

The following example demonstrates how to use <Protect /> to protect content by checking if the user has a plan.

app/protected/bronze/page.tsx
import { Protect } from '@clerk/nextjs'

export default function ProtectPage() {
  return (
    <Protect
      plan="bronze"
      fallback={<p>Sorry, only subscribers to the Bronze plan can access this content.</p>}
    >
      <p>Welcome, Bronze subscriber!</p>
    </Protect>
  )
}
src/bronze.tsx
import { Protect } from '@clerk/clerk-react'

export default function Page() {
  return (
    <Protect
      plan="bronze"
      fallback={<p>Sorry, only subscribers to the Bronze plan can access this content.</p>}
    >
      <p>Welcome, Bronze subscriber!</p>
    </Protect>
  )
}
src/pages/bronze.astro
---
import { Protect } from '@clerk/astro/components'
---

<Protect plan="bronze">
  <p slot="fallback">Sorry, only subscribers to the Bronze plan can access this content.</p>
  <p>Welcome, Bronze subscriber!</p>
</Protect>
app/(billing)/bronze.tsx
import { Protect } from '@clerk/clerk-expo'
import { Text } from 'react-native'

export default function Page() {
  return (
    <Protect
      plan="bronze"
      fallback={<Text>Sorry, only subscribers to the Bronze plan can access this content.</Text>}
    >
      <Text>Welcome, Bronze subscriber!</Text>
    </Protect>
  )
}
app/routes/bronze.tsx
import { Protect } from '@clerk/react-router'

export default function BronzePage() {
  return (
    <Protect
      plan="bronze"
      fallback={<p>Sorry, only subscribers to the Bronze plan can access this content.</p>}
    >
      <p>Welcome, Bronze subscriber!</p>
    </Protect>
  )
}
app/routes/bronze.tsx
import { Protect } from '@clerk/tanstack-react-start'
import { createFileRoute } from '@tanstack/react-router'

export const Route = createFileRoute('/bronze')({
  component: BronzePage,
})

function BronzePage() {
  return (
    <Protect
      plan="bronze"
      fallback={<p>Sorry, only subscribers to the Bronze plan can access this content.</p>}
    >
      <p>Welcome, Bronze subscriber!</p>
    </Protect>
  )
}

Render content by feature

The following example demonstrates how to use <Protect /> to protect content by checking if the user has a feature.

app/protected/premium-access/page.tsx
import { Protect } from '@clerk/nextjs'

export default function Page() {
  return (
    <Protect
      feature="premium_access"
      fallback={
        <p>Sorry, only subscribers with the Premium Access feature can access this content.</p>
      }
    >
      <p>Congratulations! You have access to the Premium Access feature.</p>
    </Protect>
  )
}
src/premium-access.tsx
import { Protect } from '@clerk/clerk-react'

export default function Page() {
  return (
    <Protect
      feature="premium_access"
      fallback={
        <p>Sorry, only subscribers with the Premium Access feature can access this content.</p>
      }
    >
      <p>Congratulations! You have access to the Premium Access feature.</p>
    </Protect>
  )
}
src/pages/premium-access.astro
---
import { Protect } from '@clerk/astro/components'
---

<Protect feature="premium_access">
  <p slot="fallback">
    Sorry, only subscribers with the Premium Access feature can access this content.
  </p>
  <p>Congratulations! You have access to the Premium Access feature.</p>
</Protect>
app/(billing)/premium-access.tsx
import { Protect } from '@clerk/clerk-expo'
import { Text } from 'react-native'

export default function Page() {
  return (
    <Protect
      feature="premium_access"
      fallback={
        <Text>
          Sorry, only subscribers with the Premium Access feature can access this content.
        </Text>
      }
    >
      <Text>Congratulations! You have access to the Premium Access feature.</Text>
    </Protect>
  )
}
app/routes/premium-access.tsx
import { Protect } from '@clerk/react-router'

export default function PremiumAccessPage() {
  return (
    <Protect
      plan="premium_access"
      fallback={
        <p>Sorry, only subscribers with the Premium Access feature can access this content.</p>
      }
    >
      <p>Congratulations! You have access to the Premium Access feature.</p>
    </Protect>
  )
}
app/routes/premium-access.tsx
import { Protect } from '@clerk/tanstack-react-start'
import { createFileRoute } from '@tanstack/react-router'

export const Route = createFileRoute('/premium-access')({
  component: PremiumAccessPage,
})

function PremiumAccessPage() {
  return (
    <Protect
      plan="premium_access"
      fallback={
        <p>Sorry, only subscribers with the Premium Access feature can access this content.</p>
      }
    >
      <p>Congratulations! You have access to the Premium Access feature.</p>
    </Protect>
  )
}

Render content conditionally

The following example uses <Protect>'s condition prop to conditionally render its children if the user has the correct role.

app/dashboard/settings/page.tsx
import type { PropsWithChildren } from 'react'
import { Protect } from '@clerk/nextjs'

export default function Page() {
  return (
    <Protect
      condition={(has) => has({ role: 'org:admin' }) || has({ role: 'org:billing_manager' })}
      fallback={<p>Only an Admin or Billing Manager can access this content.</p>}
    >
      <p>The settings page.</p>
    </Protect>
  )
}
src/settings.tsx
import { Protect } from '@clerk/clerk-react'

export default function Page() {
  return (
    <Protect
      condition={(has) => has({ role: 'org:admin' }) || has({ role: 'org:billing_manager' })}
      fallback={<p>Only an Admin or Billing Manager can access this content.</p>}
    >
      <p>The settings page.</p>
    </Protect>
  )
}
---
import { Protect } from '@clerk/astro/components'
---

<Protect condition={(has) => has({ role: 'org:admin' }) || has({ role: 'org:billing_manager' })}>
  <p slot="fallback">Only an Admin or Billing Manager can access this content.</p>
  <p>The settings page.</p>
</Protect>
app/dashboard/settings/page.tsx
import { Protect } from '@clerk/clerk-expo'
import { Text } from 'react-native'

export default function Page() {
  return (
    <Protect
      condition={(has) => has({ role: 'org:admin' }) || has({ role: 'org:billing_manager' })}
      fallback={<Text>Only an Admin or Billing Manager can access this content.</Text>}
    >
      <Text>The settings page.</Text>
    </Protect>
  )
}
app/routes/settings.tsx
import { Protect } from '@clerk/react-router'

export default function SettingsPage() {
  return (
    <Protect
      condition={(has) => has({ role: 'org:admin' }) || has({ role: 'org:billing_manager' })}
      fallback={<p>Only an Admin or Billing Manager can access this content.</p>}
    >
      <p>The settings page.</p>
    </Protect>
  )
}
app/routes/settings.tsx
import { Protect } from '@clerk/tanstack-react-start'
import { createFileRoute } from '@tanstack/react-router'

export const Route = createFileRoute('/settings')({
  component: SettingsPage,
})

function SettingsPage() {
  return (
    <Protect
      condition={(has) => has({ role: 'org:admin' }) || has({ role: 'org:billing_manager' })}
      fallback={<p>Only an Admin or Billing Manager can access this content.</p>}
    >
      <p>The settings page.</p>
    </Protect>
  )
}
<script setup>
import { Protect } from '@clerk/vue'
</script>

<template>
  <Protect :condition="(has) => has({ role: 'org:admin' }) || has({ role: 'org:billing_manager' })">
    <template #fallback>
      <p>Only an Admin or Billing Manager can access this content.</p>
    </template>
    <p>The settings page.</p>
  </Protect>
</template>

Feedback

What did you think of this content?

Last updated on