Clerk Integration
The Clerk integration connects Clerk's React and backend SDKs to the Farm runtime. Farm wraps the app in ClerkProvider and can authenticate matched requests, while Clerk remains responsible for UI, users, sessions, organizations, and account flows.
Farm does not create Clerk login, callback, session, or logout API routes.
Add Clerk
farm add integration clerk --ui
Configure
import { clerk } from "@farmjs/integrations/clerk";export const appIntegrations = { auth: clerk({ publishableKey: process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY, secretKey: process.env.CLERK_SECRET_KEY, signInUrl: "/sign-in", signUpUrl: "/sign-up", protectedRoutes: ["/dashboard(.*)"], }),} as const;
The keys can be omitted from the call when the environment variables are set.
Environment variables
| Variable | Required | Purpose |
|---|---|---|
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY |
Yes | Preferred publishable key name. |
CLERK_PUBLISHABLE_KEY |
Alternative | Fallback environment name for the publishable key. |
CLERK_SECRET_KEY |
Yes | Used by @clerk/backend to authenticate requests. |
Install @clerk/react and @clerk/backend in the application. Farm loads the React provider at render time and the backend client inside protected-route middleware.
Create sign-in and sign-up pages
signInUrl and signUpUrl tell Farm where your Clerk pages live. They do not create those pages.
"use client";import { SignIn } from "@clerk/react";export default function SignInPage() { return ( <SignIn path="/sign-in" routing="path" signUpUrl="/sign-up" fallbackRedirectUrl="/dashboard" /> );}
Create the matching sign-up page with Clerk's SignUp component.
Use Clerk in the app
Because Farm registers ClerkProvider, client components can use Clerk directly:
"use client";import { SignedIn, SignedOut, SignInButton, UserButton } from "@clerk/react";export function AccountMenu() { return ( <> <SignedOut> <SignInButton /> </SignedOut> <SignedIn> <UserButton /> </SignedIn> </> );}
Use Clerk's hooks and backend APIs for session, user, and organization data. There is no api.auth.session operation for this integration.
Protect app routes
clerk({ signInUrl: "/sign-in", protectedRoutes: ["/dashboard(.*)", "/settings(.*)"],});
For a matched request, Farm calls authenticateRequest from @clerk/backend:
- authenticated requests continue to the page or API handler;
- Clerk handshake and cookie responses are forwarded;
- signed-out requests receive a
307redirect tosignInUrl; - the original pathname is sent as Clerk's
redirect_url.
Authorized parties
By default, Clerk accepts the current request origin as an authorized party. Set an explicit list when the app has multiple trusted origins:
clerk({ authorizedParties: ["https://app.example.com", "https://admin.example.com"],});
This is especially useful when protecting against cookie misuse across sibling domains.
Provider props
Pass additional ClerkProvider props through providerProps:
clerk({ providerProps: { appearance: { variables: { colorPrimary: "#111111", }, }, },});
publishableKey is supplied automatically and can still be combined with these props.
Options
| Option | Default | Use |
|---|---|---|
publishableKey |
Clerk publishable key env | Client-safe Clerk key. |
secretKey |
CLERK_SECRET_KEY |
Server Clerk key. |
signInUrl |
/sign-in |
App-owned Clerk sign-in page. |
signUpUrl |
/sign-up |
App-owned Clerk sign-up page. |
protectedRoutes |
None | One matcher or a list of matchers. |
authorizedParties |
Current origin | Origins accepted by Clerk request authentication. |
providerProps |
{} |
Additional props for ClerkProvider. |
Production checklist
- Keep
CLERK_SECRET_KEYout of client code. - Configure Clerk's allowed origins and redirect URLs.
- Create both sign-in and sign-up catch-all pages.
- Test Clerk handshake redirects as well as normal signed-out redirects.
- Verify organization switching on every tenant-scoped route.