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
notificationCenterSetupdev-task — JWKS URL + claim paths foridandemail. - 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
| Situation | Recommended mode |
|---|---|
| Already using Firebase Auth | Firebase |
| Custom auth, want server-minted token | Backend Token |
| Using Auth0 / Clerk / Cognito / Supabase Auth / any JWKS-publishing IDP | PubliclySignedJwt |
| Local dev only | None |
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
ThenotificationCenterSetup dev-task in the dashboard guides you through:
Provide the JWKS URL
Paste your IDP’s JWKS endpoint. Examples:
- Auth0 —
https://<tenant>.auth0.com/.well-known/jwks.json - Clerk —
https://<frontend-api>.clerk.accounts.dev/.well-known/jwks.json - Cognito —
https://cognito-idp.<region>.amazonaws.com/<userPoolId>/.well-known/jwks.json - Supabase Auth —
https://<project-ref>.supabase.co/auth/v1/jwks
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.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).
_.get — dotted paths and bracketed segments work the same.Frontend setup
Your call site doesn’t referenceauthType: "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:
- Auth0
- Clerk
- Cognito
- Supabase
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:- Resolve the public key from the JWKS URL using the JWT’s
kidheader. jsonwebtoken.verify(token, key, { issuer, audience })— rejects on signature mismatch, wrong issuer, or wrong audience.- Extract
idandemailfrom the verified payload via the configured paths. - Mint a Firebase custom token for the widget session, embedding
{ user, apiKey, organisation }claims.
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:| Claim | Used as | Notes |
|---|---|---|
(configured paths.id) | userId | String. Stable per user. Often sub. |
(configured paths.email) | userEmail | String. Doesn’t have to match anything else; used for display. |
iss | matched against expected issuer | Must equal the value configured in the dashboard. |
aud | matched against expected audience | Must equal the value configured in the dashboard. |
exp | standard expiry | Token rejected if expired. |
FAQ
Auth0 — which claims should I configure?
Auth0 — which claims should I configure?
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 — same?
Clerk — same?
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.Why is there no SDK shorthand for this mode?
Why is there no SDK shorthand for this mode?
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.
Why do I see `CustomRsaJwt` in dashboard logs?
Why do I see `CustomRsaJwt` in dashboard logs?
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.Verification fails with `kid not found`.
Verification fails with `kid not found`.
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.My token verifies but the widget says `auth/invalid-token-signature`.
My token verifies but the widget says `auth/invalid-token-signature`.
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.Can I rotate my IDP keys without downtime?
Can I rotate my IDP keys without downtime?
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.