Browse documentation

Authenticate with Clerk

Protect the admin with Clerk and enforce a role from session claims.

This guide connects the existing Clerk session to FlowPanel and restricts the admin to users whose public metadata role is admin.

Prerequisites

Clerk must already work in the host Next.js application. Install its Next.js SDK if needed:

pnpm add @clerk/nextjs

Protect the route with Clerk

Configure Clerk middleware using the same admin and API paths generated by FlowPanel. The middleware is the first authentication boundary; FlowPanel's server handlers remain the authorization boundary.

Wrap the root application in ClerkProvider according to the installed Clerk version. The complete maintained example is examples/with-clerk.

Configure FlowPanel auth

import { defineAdmin } from "@flowpanel/kit";
import { withClerk } from "@flowpanel/kit/auth";

export default defineAdmin({
  adapter,
  auth: withClerk({
    requireRole: "admin",
    signInUrl: "/sign-in",
    forbiddenUrl: "/",
  }),
  resources,
});

By default, withClerk reads publicMetadata.role and falls back to guest. It uses the Clerk user ID as the actor ID for audit and per-user rate limiting. Supply role or userId only when your claims use a different shape.

Put the role in the session

Set publicMetadata.role for the user and include public_metadata in the Clerk session token as publicMetadata. A database role that is not present in the session claims cannot be read by withClerk without a custom resolver.

Treat metadata changes as authentication state changes. Sign out and back in, or otherwise refresh the Clerk session, before testing a new role.

Verify the boundary

Test all three cases:

  1. no Clerk session: the admin page follows signInUrl, while API requests are rejected;
  2. signed in without admin: the page follows forbiddenUrl, while API requests return forbidden;
  3. signed in as admin: the page and resource API succeed.

Also call one action route as a non-admin. A hidden button is not proof; the server response is.

Production notes and failure modes

  • withClerk throws a clear startup/runtime error when @clerk/nextjs is absent.
  • Missing or misspelled public metadata resolves to guest and should fail the role gate.
  • Keep API and stream paths inside the Clerk middleware matcher.
  • Do not use devAuth() or the generated session stub in production.

Continue with Roles and permissions. Exact options are generated in Configuration reference.