Authentication
The visitor trust ladder — anonymous, prefilled, and verified-identified — and which proof to use
By default the widget works fully anonymously. When you want conversations attributed to a known user — and when you want to gate sensitive data behind a real identity — you identify the visitor with a cryptographic proof produced on your server.
The trust ladder
| Level | Established by | Server trust | Can gate sensitive data? |
|---|---|---|---|
| Anonymous | A random visitor id in localStorage | none | No |
| Prefill (unverified) | Host passes name / email / phone | none | No |
| Verified-identified | A cryptographic proof made outside the browser (JWT, HMAC, Google, or passkey) | verified user id | Yes |
The rule: the browser only ever carries a proof — it never produces one. Anything sensitive is gated on the verified identity and scoped to the verified user id, never to a raw email.
The proofs
| Proof | Trust anchor | Expires? | Needs a host backend? | Use when |
|---|---|---|---|---|
| Signed JWT (HS256) | Your integration's shared secret | Yes (exp) | Yes | Recommended for any site with a backend and logged-in users. |
HMAC (user_hash) | Shared secret | Never | Yes | Legacy / Intercom-style migration. Prefer JWT. |
| Google (FedCM) | Google's keys | Yes | No | Public sites with no backend — let visitors sign in with Google. |
| Passkey (WebAuthn) | The visitor's device | Per use | No | In-page embeds wanting passwordless sign-in. |
You can attach profile data (name, email, phone, custom attributes) to any proof.
Which should I use?
- You have a backend and your own login. Use a signed JWT. It's short-lived, carries a trusted profile, and self-revokes.
- You're migrating from Intercom's
user_hash. The HMAC proof is the drop-in equivalent. Plan to move to JWT. - No backend at all. Enable Google sign-in or passkeys and the widget handles it in-panel.
The shared secret
JWT and HMAC proofs are both signed with your integration's shared secret — the value revealed once at widget creation. It is encrypted at rest, never sent to the browser, and never appears in the widget's public config. Sign server-side only; if it ever reaches client JavaScript, treat it as leaked and rotate it.
Anonymous still works
Even with Require auth enabled, an anonymous visitor still gets a session and can read content, react, and browse. requireAuth gates only the messenger — an unverified visitor's outbound message is refused and the composer is replaced with a sign-in panel. See Sessions.