Skip to main content
Clerk is your source of truth. UserKit needs to know which of your users is on the page, and it will not take the page’s word for it — your server signs the claim.
The identity secret never enters the bundle. Never prefix it with NEXT_PUBLIC_, never render it into HTML, never send it to the browser to save a round trip. Whoever holds it can mint a verified session for any of your users.
The contract is the one on the federated identity page and nothing here changes it:

What Clerk supplies

One value: userId, the user_… id Clerk’s own webhooks name. That is the external_id.
lib/clerk.ts
auth() reads the session Clerk’s middleware already verified. Decoding the __session cookie yourself and signing its sub would be signing a value the browser chose.
auth() needs clerkMiddleware() mounted, or it throws rather than answering with a null userId. That is the right failure: “I could not tell” must never be read as “signed out”.

The server half

app/api/userkit-boot/route.ts

The client half

getState().verified is true only when the HMAC checked out. Signed in to Clerk with verified: false means either the secret belongs to the other environment or the message signed was not exactly the external_id.

Configuration

Clerk organizations are not the identity

orgId is a second dimension, and signing userId + orgId into one message would make one person two contacts. UserKit’s own team object is the customer, resolved per request from X-Customer-Id — map Clerk’s organization onto that, not onto the external_id.

What does not travel

A Clerk user carries verified email addresses. They do not become identities in UserKit: an email sent through /v1/boot is stored as an attribute, does not resolve to an existing contact and does not become an identity edge. The HMAC proves the external_id and only the external_id. To prove an address, send a magic link or an email code — the two flows that arrive in it.

The full example

A runnable Next app with these files, an .env.example and the pieces this page leaves out.