CL

clerk-enterprise-rbac

Guidelines for setting up enterprise SSO, custom roles, and organization management using the Clerk platform.

Install

mkdir -p .claude/skills/clerk-enterprise-rbac && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/4767" && unzip -o skill.zip -d .claude/skills/clerk-enterprise-rbac && rm skill.zip

Installs to .claude/skills/clerk-enterprise-rbac

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

Configure enterprise SSO, role-based access control, and organization
69 charsno explicit “when” trigger
Advanced

Key capabilities

  • Enable Clerk Organizations and integrate UI components like OrganizationSwitcher.
  • Define custom roles and permissions within the Clerk Dashboard.
  • Implement RBAC middleware to protect routes based on user roles.
  • Perform permission checks in server components using `auth()`.
  • Conduct permission checks in client components using `Protect` and `useAuth()`.

How it works

The skill guides through enabling Clerk Organizations, defining roles and permissions in the dashboard, and implementing middleware and component-level checks to enforce access control based on these definitions.

Inputs & outputs

You give it
Application requirements for enterprise SSO, role-based access control, or organization management.
You get back
Configured Clerk enterprise features, including UI components, custom roles, and protected routes.

When to use clerk-enterprise-rbac

  • Integrating SAML/OIDC SSO
  • Setting up organization-based multi-tenant access
  • Defining custom roles and permissions
  • Implementing organization switcher UI components

About this skill

Clerk Enterprise RBAC

Overview

Implement enterprise-grade role-based access control, organization management, and SSO with Clerk. Covers custom roles and permissions, organization lifecycle, multi-tenant access patterns, SAML/OIDC SSO, and the Backend API for programmatic role management (released Nov 2025).

Prerequisites

  • Clerk Pro or Enterprise plan (Organizations + SSO require paid plan)
  • Organizations feature enabled in Clerk Dashboard > Organizations > Settings
  • Next.js 14+ with App Router (examples use @clerk/nextjs)

Instructions

Step 1: Enable Organizations and Add UI Components

// app/org-selector/page.tsx
import { OrganizationSwitcher, OrganizationProfile } from '@clerk/nextjs'

export default function OrgPage() {
  return (
    <div className="p-8">
      <h1>Select Organization</h1>
      <OrganizationSwitcher
        hidePersonal={false}
        afterSelectOrganizationUrl="/dashboard"
        afterCreateOrganizationUrl="/dashboard"
      />
      <div className="mt-8">
        <OrganizationProfile />
      </div>
    </div>
  )
}

Step 2: Define Custom Roles and Permissions

Configure in Clerk Dashboard > Organizations > Roles and Permissions.

Default roles (built-in):

RoleKeyBuilt-in Permissions
Adminorg:adminFull org management (members, settings, billing)
Memberorg:memberView org, read-only access

Custom permissions (create in Dashboard > Organizations > Permissions):

PermissionKeyDescription
Read dataorg:data:readView organization resources
Write dataorg:data:writeCreate/update resources
Delete dataorg:data:deleteDelete resources
Manage billingorg:billing:manageAccess billing settings
View analyticsorg:analytics:readAccess analytics dashboard

Custom roles (create in Dashboard > Organizations > Roles):

RolePermissionsUse Case
org:managerdata:read, data:write, analytics:readContent managers
org:viewerdata:readRead-only stakeholders
org:billing_admindata:read, billing:manageFinance team

Step 3: RBAC Middleware — Route Protection by Role

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

const isPublicRoute = createRouteMatcher([
  '/',
  '/sign-in(.*)',
  '/sign-up(.*)',
  '/api/webhooks(.*)',
])
const isAdminRoute = createRouteMatcher(['/admin(.*)'])
const isManagerRoute = createRouteMatcher(['/manage(.*)'])

export default clerkMiddleware(async (auth, req) => {
  if (isPublicRoute(req)) return

  if (isAdminRoute(req)) {
    // Only org:admin can access /admin/*
    await auth.protect({ role: 'org:admin' })
  } else if (isManagerRoute(req)) {
    // org:admin OR org:manager can access /manage/*
    await auth.protect((has) =>
      has({ role: 'org:admin' }) || has({ role: 'org:manager' })
    )
  } else {
    // All other routes just require authentication
    await auth.protect()
  }
})

Step 4: Permission Checks in Server Components

// app/admin/page.tsx
import { auth } from '@clerk/nextjs/server'
import { redirect } from 'next/navigation'

export default async function AdminPage() {
  const { userId, orgId, orgRole, has } = await auth()

  if (!userId) redirect('/sign-in')
  if (!orgId) redirect('/org-selector')

  // Permission-based checks (preferred over role-based)
  const canManageMembers = has({ permission: 'org:sys_memberships:manage' })
  const canWriteData = has({ permission: 'org:data:write' })
  const canDeleteData = has({ permission: 'org:data:delete' })
  const canViewAnalytics = has({ permission: 'org:analytics:read' })

  return (
    <div>
      <h1>Admin Panel</h1>
      <p>Current role: {orgRole}</p>

      <nav>
        {canManageMembers && <a href="/admin/members">Manage Members</a>}
        {canWriteData && <a href="/admin/content">Content Management</a>}
        {canDeleteData && <a href="/admin/danger-zone">Danger Zone</a>}
        {canViewAnalytics && <a href="/admin/analytics">Analytics</a>}
      </nav>
    </div>
  )
}

Step 5: Permission Checks in Client Components

'use client'
import { Protect, useOrganization, useAuth } from '@clerk/nextjs'

export function AdminSection() {
  const { organization } = useOrganization()
  const { has } = useAuth()

  return (
    <div>
      <h2>{organization?.name}</h2>

      {/* Declarative: Protect component with fallback */}
      <Protect
        role="org:admin"
        fallback={<p>You need admin access to view this section.</p>}
      >
        <DangerZone />
      </Protect>

      {/* Permission-based rendering */}
      <Protect permission="org:data:write">
        <EditForm />
      </Protect>

      {/* Imperative: has() for conditional logic */}
      {has?.({ permission: 'org:analytics:read' }) && (
        <AnalyticsDashboard />
      )}
    </div>
  )
}

Step 6: Organization Member Management via Backend API

// app/api/org/members/route.ts
import { auth, clerkClient } from '@clerk/nextjs/server'

export async function GET() {
  const { orgId, has } = await auth()
  if (!orgId) return Response.json({ error: 'No org selected' }, { status: 400 })
  if (!has({ permission: 'org:sys_memberships:read' })) {
    return Response.json({ error: 'Forbidden' }, { status: 403 })
  }

  const client = await clerkClient()
  const members = await client.organizations.getOrganizationMembershipList({
    organizationId: orgId,
  })

  return Response.json({
    members: members.data.map(m => ({
      userId: m.publicUserData?.userId,
      name: `${m.publicUserData?.firstName} ${m.publicUserData?.lastName}`,
      email: m.publicUserData?.identifier,
      role: m.role,
      joinedAt: m.createdAt,
    })),
  })
}

export async function POST(req: Request) {
  const { orgId, userId, has } = await auth()
  if (!orgId || !has({ permission: 'org:sys_memberships:manage' })) {
    return Response.json({ error: 'Forbidden' }, { status: 403 })
  }

  const { emailAddress, role } = await req.json()
  const client = await clerkClient()

  const invitation = await client.organizations.createOrganizationInvitation({
    organizationId: orgId,
    emailAddress,
    role: role || 'org:member',
    inviterUserId: userId!,
  })

  return Response.json({ invitation: { id: invitation.id, emailAddress, role } })
}

Step 7: Programmatic Role/Permission Management (Backend API)

// lib/org-roles.ts — manage roles and permissions via API (released Nov 2025)
import { clerkClient } from '@clerk/nextjs/server'

export async function createCustomRole(orgId: string) {
  const client = await clerkClient()

  // Create a custom permission
  await client.organizations.createOrganizationPermission({
    organizationId: orgId,
    name: 'Manage reports',
    key: 'org:reports:manage',
    description: 'Create, edit, and delete reports',
  })

  // Create a custom role with that permission
  await client.organizations.createOrganizationRole({
    organizationId: orgId,
    name: 'Report Manager',
    key: 'org:report_manager',
    description: 'Can manage all reports',
    permissions: ['org:reports:manage', 'org:data:read'],
  })
}

// Update a member's role
export async function updateMemberRole(
  orgId: string,
  userId: string,
  newRole: string
) {
  const client = await clerkClient()
  const memberships = await client.organizations.getOrganizationMembershipList({
    organizationId: orgId,
  })

  const membership = memberships.data.find(
    m => m.publicUserData?.userId === userId
  )
  if (!membership) throw new Error('User is not a member of this organization')

  await client.organizations.updateOrganizationMembership({
    organizationId: orgId,
    userId,
    role: newRole,
  })
}

Step 8: SAML SSO Configuration

Configure in Clerk Dashboard > SSO Connections > Add SAML Connection:

  1. ACS URL: https://<your-clerk-frontend-api>.clerk.accounts.dev/v1/saml/acs
  2. Entity ID: https://<your-clerk-frontend-api>.clerk.accounts.dev/v1/saml/metadata
  3. Upload IdP metadata XML from your provider (Okta, Azure AD, Google Workspace)
  4. Map SAML attributes: email, firstName, lastName
// Enforce SSO for specific email domains
// Clerk Dashboard > Organizations > Settings > "Verified domains"
// Add your company domain (e.g., acme.com)
// Users with @acme.com emails will be forced through SSO

Error Handling

ErrorCauseSolution
orgId is nullNo active organizationRedirect to org selector, show <OrganizationSwitcher />
has() returns falseRole/permission not assignedCheck assignment in Dashboard > Organizations > Members
Permission denied on middlewareUser lacks required roleVerify route matcher maps to correct role
SSO login failsMisconfigured IdP metadataVerify ACS URL and Entity ID in IdP settings
Invitation failsEmail already a memberCheck membership before inviting
Custom role not visibleCreated via API, not DashboardRoles created via API are org-scoped, not instance-wide

Enterprise Considerations

  • Roles and permissions are embedded in the session JWT -- no extra network requests needed for authorization checks
  • Custom roles created in the Dashboard are instance-wide; roles created via Backend API are organization-scoped
  • For multi-tenant SaaS, combine Organizations with tenant-scoped database queries (WHERE org_id = :orgId)
  • Session claims include org_id, org_role, and org_permissions -- available in middleware without API calls
  • Verified domains + SAML SSO enable "just-in-time provisioning" -- users auto-join the org on first SSO sign-in
  • Consider the org:sys_* system permissions (`sys_memberships:m

Content truncated.

When not to use it

  • When the application does not require multi-tenant access control.
  • When the project does not use Clerk for authentication and authorization.

Prerequisites

Clerk Pro or Enterprise planOrganizations feature enabled in Clerk DashboardNext.js 14+ with App Router

Limitations

  • Requires a Clerk Pro or Enterprise plan.
  • The Backend API for programmatic role management is released in November 2025.

How it compares

This skill provides specific Clerk configurations and code examples for enterprise RBAC and SSO, offering a structured approach compared to manually integrating these features.

Compared to similar skills

clerk-enterprise-rbac side by side with the closest alternatives in the catalog.

SkillInstallsUpdatedSafetyDifficulty
clerk-enterprise-rbac (this skill)127dNo flagsAdvanced
nextjs-supabase-auth126moNo flagsIntermediate
better-auth59moReviewIntermediate
auth-patterns77moReviewIntermediate

Try saying

Example prompts that trigger this skill in your AI assistant.

More by jeremylongshore

View all by jeremylongshore

analyzing-logs

jeremylongshore

Analyze application logs to detect performance issues, identify error patterns, and improve stability by extracting key insights.

14123

ollama-setup

jeremylongshore

Configure auto-configure Ollama when user needs local LLM deployment, free AI alternatives, or wants to eliminate hosted API costs. Trigger phrases: "install ollama", "local AI", "free LLM", "self-hosted AI", "replace OpenAI", "no API costs". Use when appropriate context detected. Trigger with relevant phrases based on skill purpose.

1167

backtesting-trading-strategies

jeremylongshore

Backtest crypto and traditional trading strategies against historical data. Calculates performance metrics (Sharpe, Sortino, max drawdown), generates equity curves, and optimizes strategy parameters. Use when user wants to test a trading strategy, validate signals, or compare approaches. Trigger with phrases like "backtest strategy", "test trading strategy", "historical performance", "simulate trades", "optimize parameters", or "validate signals".

1071

generating-database-seed-data

jeremylongshore

Process this skill enables AI assistant to generate realistic test data and database seed scripts for development and testing environments. it uses faker libraries to create realistic data, maintains relational integrity, and allows configurable data volumes. u... Use when working with databases or data models. Trigger with phrases like 'database', 'query', or 'schema'.

1033

cursor-codebase-indexing

jeremylongshore

Execute set up and optimize Cursor codebase indexing. Triggers on "cursor index setup", "codebase indexing", "index codebase", "cursor semantic search". Use when working with cursor codebase indexing functionality. Trigger with phrases like "cursor codebase indexing", "cursor indexing", "cursor".

885

testing-mobile-apps

jeremylongshore

Execute mobile app testing on iOS and Android devices/simulators. Use when performing specialized testing. Trigger with phrases like "test mobile app", "run iOS tests", or "validate Android functionality".

810

You might also like

nextjs-supabase-auth

davila7

Expert integration of Supabase Auth with Next.js App Router Use when: supabase auth next, authentication next.js, login supabase, auth middleware, protected route.

1259

better-auth

mrgoonie

Implement authentication and authorization with Better Auth - a framework-agnostic TypeScript authentication framework. Features include email/password authentication with verification, OAuth providers (Google, GitHub, Discord, etc.), two-factor authentication (TOTP, SMS), passkeys/WebAuthn support, session management, role-based access control (RBAC), rate limiting, and database adapters. Use when adding authentication to applications, implementing OAuth flows, setting up 2FA/MFA, managing user sessions, configuring authorization rules, or building secure authentication systems for web applications.

527

auth-patterns

davepoon

This skill should be used when the user asks about "authentication in Next.js", "NextAuth", "Auth.js", "middleware auth", "protected routes", "session management", "JWT", "login flow", or needs guidance on implementing authentication and authorization in Next.js applications.

720

clerk-common-errors

jeremylongshore

Troubleshoot common Clerk errors and issues. Use when encountering authentication errors, SDK issues, or configuration problems with Clerk. Trigger with phrases like "clerk error", "clerk not working", "clerk authentication failed", "clerk issue", "fix clerk".

14

clerk-performance-tuning

jeremylongshore

Optimize Clerk authentication performance. Use when improving auth response times, reducing latency, or optimizing Clerk SDK usage. Trigger with phrases like "clerk performance", "clerk optimization", "clerk slow", "clerk latency", "optimize clerk".

14

clerk-sdk-patterns

jeremylongshore

Common Clerk SDK patterns and best practices. Use when implementing authentication flows, accessing user data, or integrating Clerk SDK methods in your application. Trigger with phrases like "clerk SDK", "clerk patterns", "clerk best practices", "clerk API usage".

22

Search skills

Search the agent skills registry