What Better Auth supplies
One value:session.user.id. That is the external_id.
lib/better-auth.ts
getSession validates against the database rather than decoding the cookie.
Here the temptation is at its strongest, because the session table is right
there — but an id the browser could choose is not something to sign.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
Better Auth with verified: false means either the secret belongs to the other
environment or the message signed was not exactly the external_id.
Configuration
What does not travel
Better Auth’s user carriesemail and emailVerified. They are statements
about your database, and 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.