Skip to content

Identity

Read state and targeting depend on knowing who the user is. The browser can’t be trusted to say that itself, so rollout accepts three kinds of identity. You choose under Settings → Identity.

Mode How Targeting
Signed token Your server signs a JWT with the project’s signing secret. Yes
Your auth provider A JWT from Clerk, Auth0, Supabase Auth, … checked via JWKS. Yes
Unverified (opt-in) The SDK sends a plain user id. No

The SDK sends tokens as Authorization: Bearer <token> along with the publishable key in X-Rollout-Key.

Generate a signing secret under Settings → Identity (it starts with rollout_sig_). On your server, sign a short-lived HS256 JWT for the signed-in user.

Claim Required Description
sub Yes Your user id, any string up to 256 characters.
exp Yes Expiry. Keep it short, e.g. one hour; the SDK fetches a new token after a 401.
org No The organization or account the user belongs to.
created_at No When the user signed up, as Unix seconds or an ISO date. Older announcements start out read.
attrs No An object of custom attributes for targeting, e.g. { "plan": "pro" }.
import { SignJWT } from 'jose'
const secret = new TextEncoder().encode(process.env.ROLLOUT_SIGNING_SECRET)
export function rolloutToken(user) {
return new SignJWT({
org: user.orgId,
created_at: Math.floor(user.createdAt.getTime() / 1000),
attrs: { plan: user.plan, role: user.role },
})
.setProtectedHeader({ alg: 'HS256' })
.setSubject(user.id)
.setExpirationTime('1h')
.sign(secret)
}

Serve it from an endpoint your frontend can call, and pass a function to the SDK so it can fetch fresh tokens:

feed.token = () => fetch('/api/rollout-token').then((r) => r.text())

A project can have several active secrets; rollout accepts a token signed with any of them. Generate a new secret, deploy it to your servers, then retire the old one under Settings → Identity. Tokens signed with a retired secret are rejected.

If your users already have a JWT from an auth provider, rollout can verify it against the provider’s public keys instead. Under Settings → Identity, set:

  • JWKS URL: the provider’s key set, e.g. https://your-app.clerk.accounts.dev/.well-known/jwks.json.
  • Audience (aud): required. Tokens must be issued for this audience, and must have exp.
  • Claim mapping: which claims hold the user id (sub by default) and organization (org).

When a JWKS URL is set, signing secrets are not used.

If you allow it under Settings → Identity (“Also allow unverified users”), the SDK can pass a plain identity instead of a token:

feed.user = { id: 'user_123', org: 'org_42', createdAt: '2025-01-10T00:00:00Z' }

The SDK sends it base64url-encoded in the X-Rollout-User header. Anyone can claim any id this way, so read state can be spoofed, and targeted announcements are never shown to unverified users. Use it for prototypes or public, logged-out pages only.

Code Meaning
identity_required No token and no unverified user was sent.
invalid_token Bad signature, wrong audience, missing sub/exp, or expired.
verified_identity_required An unverified user was sent, but the project requires tokens.
origin_not_allowed The page’s origin isn’t in Settings → API keys → Allowed origins.