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 implementation-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.
  • The configuration value stored for this strategy is CustomRsaJwt — a legacy name for the same mode.
These docs always call this mode PubliclySignedJwt. The value persisted on the environment is the older name, CustomRsaJwt — same strategy, nothing to change on your side.

When to pick this mode

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 implementation-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:
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 it to /v1/users/auth; Notifizz verifies it against the JWKS configured for the environment.

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. Open the widget session for the verified identity.
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: 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.
It is the older name of this strategy, kept as the stored configuration value. PubliclySignedJwt and CustomRsaJwt are the same mode — 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.