Skip to main content

Auth integration recipes

This page collects copy-pasteable recipes for each widget auth mode against the most common backend and identity-provider stacks. The conceptual reference is in authentication overview; the per-mode details are under each auth-mode page.

TL;DR

  • backendToken — your backend exposes a token endpoint; recipes per backend framework below.
  • firebase — your frontend reads the Firebase ID token; minimal backend involvement.
  • PubliclySignedJwt — your frontend reads the IDP’s session token; configured server-side in the dashboard.
  • none — local dev only; no auth.

Backend Token recipes

Node — Express

Node — Fastify

Node — NestJS

PHP — Laravel

Python — Django

There’s no official Python SDK yet — the helper is two lines: hashlib.sha256((user_id + auth_secret).encode()).hexdigest(). The hash format is the same as client.generateHashedToken() in the Node/Java/PHP SDKs.

Ruby — Rails

Java — Spring

Frontend consumption

Pair any of the backend recipes above with this frontend snippet:

Firebase recipes

Web client

Re-mount on token refresh

Publicly-Signed JWT recipes

PubliclySignedJwt is configured server-side via the dashboard. The frontend just reads the IDP session token. Common providers:

Auth0

Clerk

Cognito

Supabase Auth

The dashboard notificationCenterSetup implementation-task captures the JWKS URL + claim paths once per environment — the same frontend code works regardless of provider once the dashboard is configured. See publicly-signed JWT for the dashboard side.

FAQ

By default, Auth0 puts the user id in sub and the email in email (when the email scope is requested). Set paths.id = "sub" and paths.email = "email". With Auth0’s namespaced custom-claims pattern, use the namespaced paths instead.
Clerk puts the user id in sub. Email needs to be added via a Clerk session token template — Clerk doesn’t include it by default. Either add email to the template, or configure paths.email to the metadata path you use.
Supabase Auth supports anonymous users with a stable user.id and a valid JWT. PubliclySignedJwt works for them; bridge to a real identity later if your campaigns expect it.
Only if staging is behind your VPN / SSO and not customer-facing. The threat model with 'none' is “anyone with the API key plus a userId can read that user’s inbox” — fine inside a controlled environment, never on the open internet.
Cross-environment IDP config. Your dev environment is probably wired to dev IDP credentials and a dev JWKS URL; prod needs the prod equivalent. Compare the dashboard auth config side-by-side; most “works on dev only” cases trace to one stale field.
state.isReady === true means auth succeeded. If unreadCount is 0, the auth is fine but no message reached this userId. Check that your campaign’s orchestrator emits this exact userId as a recipient identifier — most “empty bell” cases are auth working + recipient mismatch.

See also

Authentication overview

The four-mode model and when to pick each.

Backend tokens

client.generateHashedToken end-to-end.

Firebase auth

Pass a Firebase ID token to the widget.

Publicly-signed JWT

Auth0 / Clerk / Cognito / Supabase setup.