Skip to main content

Publicly-signed JWT widget authentication

PubliclySignedJwt is the widget auth mode for apps that already use a managed identity provider — Auth0, Clerk, Cognito, Supabase Auth, or any provider that publishes a JWKS endpoint. Unlike the other three modes, it has no SDK shorthand: the strategy is configured server-side via the dashboard, and your widget call site stays minimal.

TL;DR

  • Configured via the dashboard notificationCenterSetup dev-task — JWKS URL + claim paths for id and email.
  • The widget passes a JWT issued by your IDP to /v1/users/auth; Notifizz verifies it against the JWKS.
  • No authType: "publiclySignedJwt" in the SDK — the call site uses your existing IDP session, the dashboard wires the strategy.
  • In backend code and logs, the strategy is named CustomRsaJwt — same thing.
Customer-facing prose always uses PubliclySignedJwt. Backend code, logs, and a few dashboard internals show CustomRsaJwt — they’re the same strategy. You’ll see the alias once if you trace requests through backend logs; the rest of the time, ignore it.

When to pick this mode

SituationRecommended mode
Already using Firebase AuthFirebase
Custom auth, want server-minted tokenBackend Token
Using Auth0 / Clerk / Cognito / Supabase Auth / any JWKS-publishing IDPPubliclySignedJwt
Local dev onlyNone
PubliclySignedJwt shines when you want to decouple Notifizz from your backend availability — the widget verifies against the IDP’s JWKS, so widget auth keeps working through partial backend outages. It also reduces the surface area of authSecretKey (you don’t need it; only the public JWKS URL is configured).

Dashboard setup

The notificationCenterSetup dev-task in the dashboard guides you through:
1

Pick the strategy

In environment settings, set the widget auth strategy to PubliclySignedJwt.
2

Provide the JWKS URL

Paste your IDP’s JWKS endpoint. Examples:
  • Auth0https://<tenant>.auth0.com/.well-known/jwks.json
  • Clerkhttps://<frontend-api>.clerk.accounts.dev/.well-known/jwks.json
  • Cognitohttps://cognito-idp.<region>.amazonaws.com/<userPoolId>/.well-known/jwks.json
  • Supabase Authhttps://<project-ref>.supabase.co/auth/v1/jwks
3

Set the expected issuer and audience

The dashboard captures the iss (issuer) and aud (audience) claims your IDP emits. Notifizz rejects tokens whose claims don’t match.
4

Map the identity claims

JWTs vary in where they put the user id and email. Configure two paths:
  • paths.id — JSON path to the user identifier in the token payload (e.g. sub, https://your-app/user_id).
  • paths.email — JSON path to the email (e.g. email, https://your-app/email).
These are evaluated with lodash _.get — dotted paths and bracketed segments work the same.
Once configured, your frontend calls remain minimal — the widget reads the token from your existing IDP session.

Frontend setup

Your call site doesn’t reference authType: "publiclySignedJwt" (the SDK union doesn’t include it). Instead, you pass a jwtToken field through your IDP integration; the widget submits it to /v1/users/auth and Notifizz applies the configured strategy. The minimal pattern with each provider:
import { useAuth0 } from "@auth0/auth0-react";

const { getAccessTokenSilently } = useAuth0();
const token = await getAccessTokenSilently();

// Pass `token` to the widget. The strategy on the dashboard applies.
The token then flows into the widget exactly as for the other modes — pass it as token in your widget options. Behind the scenes the widget submits a PublicJwtSignedParams payload to /v1/users/auth and the configured RsaJwtAuthenticationStrategy handles verification.

How verification works

The verifier does:
  1. Resolve the public key from the JWKS URL using the JWT’s kid header.
  2. jsonwebtoken.verify(token, key, { issuer, audience }) — rejects on signature mismatch, wrong issuer, or wrong audience.
  3. Extract id and email from the verified payload via the configured paths.
  4. Mint a Firebase custom token for the widget session, embedding { user, apiKey, organisation } claims.
If the environment doesn’t have a public key configured, the request fails with auth/no-public-key-registered (401). If the token verifies but id/email extraction fails, the request fails with auth/invalid-token-signature.

Required JWT claims

The token must contain — at the paths you configure in the dashboard:
ClaimUsed asNotes
(configured paths.id)userIdString. Stable per user. Often sub.
(configured paths.email)userEmailString. Doesn’t have to match anything else; used for display.
issmatched against expected issuerMust equal the value configured in the dashboard.
audmatched against expected audienceMust equal the value configured in the dashboard.
expstandard expiryToken rejected if expired.
Custom claims beyond these are ignored by Notifizz — but you can forward them via your event properties if a campaign needs them.

FAQ

By default, Auth0 puts the user id in sub and the email in email (when the email scope is requested). Configure paths.id = "sub" and paths.email = "email". If you use Auth0’s “namespaced custom claims” pattern, configure the namespaced paths instead (e.g. paths.email = "https://your-app.com/email").
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 point at the Clerk metadata path you use.
Because the strategy is decided per-environment and changing it shouldn’t require a frontend deploy. The dashboard owns the JWKS URL, expected issuer, audience, and claim paths — your code just passes the token. This keeps the SDK surface to three options and pushes config to operators.
Backend internal name for the same strategy. Customer-facing prose always uses PubliclySignedJwt; logs and a few dashboard internals haven’t been renamed. Treat them as identical.
The JWT’s kid header doesn’t match any key returned by your JWKS URL. Three causes: (1) the JWKS URL is wrong; (2) your IDP rotated keys and the cached keys are stale (Notifizz refetches the JWKS automatically; wait a minute); (3) the JWT was issued in a different IDP environment than the one whose JWKS you configured.
The verifier ran but the paths.id or paths.email lookups returned non-strings. Inspect the JWT payload — the path you configured doesn’t resolve to a string. Use a JWT debugger to see exact paths, then update the dashboard config.
Yes — that’s a strength of PubliclySignedJwt. JWKS endpoints typically expose multiple keys during rotation; tokens signed with the old key keep verifying until they expire, new tokens use the new key. Notifizz follows the JWKS — no manual coordination needed.

See also

Authentication overview

The four-mode model and when to pick each.

Backend tokens

Mint a server-side HMAC token instead of a JWT.

Firebase auth

Skip the dashboard configuration — Firebase Auth has built-in support.

Notification Center overview

Lifecycle, state model, custom bell, headless mode.