Identity and targeting
Decide who should see which updates.
Most teams can start with a very small widget token. When you need different customers, plans, or internal users to see different updates, add a few extra claims and let Chainlog handle the filtering for you.
What the widget token does
This token is the handoff between your backend and the widget. It tells Chainlog who the user is and what broad access they have.
import { SignJWT } from "jose";
export async function GET() {
const user = await getCurrentUserFromYourApp();
if (!user) return Response.json({ error: "Unauthorized" }, { status: 401 });
const now = Math.floor(Date.now() / 1000);
const secret = new TextEncoder().encode(process.env.CHAINLOG_WIDGET_CREDENTIAL_SECRET!);
const token = await new SignJWT({
tenant: process.env.CHAINLOG_TENANT_ID!,
sub: user.id,
aud: "chainlog-widget",
kid: process.env.CHAINLOG_WIDGET_CREDENTIAL_ID!,
entitlements: user.entitlements || [],
contextModule: user.contextModule || null,
internalAccess: Boolean(user.canViewInternalUpdates),
iat: now,
exp: now + 600,
})
.setProtectedHeader({ alg: "HS256", typ: "JWT" })
.sign(secret);
return Response.json({ token, expiresInSeconds: 600 });
}| Claim | Required | What it means |
|---|---|---|
| tenant | Required | Which Chainlog workspace the widget is allowed to read from. |
| sub | Required | A stable user ID so Chainlog can evaluate visibility and rate limits correctly. |
| aud | Required, "chainlog-widget" | Marks the token as a widget token. |
| kid | Recommended | Tells Chainlog which widget credential signed the token. |
| entitlements | Optional | Plan or capability tags such as pro or enterprise. |
| internalAccess | Optional | Lets staff or support users see internal-only updates. |
| showAllUpdates | Optional | Broadens visibility when your product allows a user to see everything. |
| contextModule | Optional | A default product area such as billing, platform, or dashboard. |
| iat / exp | Required | Issued-at and expiration timestamps. Keep the token short-lived. |
Start simple, then add targeting later
Every widget request is authenticated, but most products do not need a complex claim set right away.
Minimal claim set
Start with tenant, sub, aud, kid, iat, and exp. That is enough for the default signed-in widget setup.
Targeted claim set
Add entitlements, internalAccess, or contextModule only when you need plan-specific, internal-only, or product-area-specific filtering.
Recommended default
Start with tenant, sub, aud, kid, iat, and exp. Add extra claims only when a real audience rule appears.
When to use each targeting claim
Think of claims as coarse access rules. Chainlog combines them with each entry’s own visibility settings.
entitlementsare best for plan, tier, or capability access such asproorenterprise.contextModuleis best for product-area defaults such asbilling,reports, ordashboard.internalAccessshould be reserved for employee or support views where internal-only entries are allowed.- Tenant runtime defaults control presentation, not access. They can set mode, theme, label, and sizing, but they do not replace entry visibility rules.
window.ChainlogWidget.init({
tenantId: "CHAINLOG_TENANT_ID",
useTenantDefaults: true,
tokenProvider: async () => {
const response = await fetch("/api/widget-token", {
credentials: "include",
});
const { token, expiresInSeconds } = await response.json();
return { token, expiresInSeconds };
},
});Claims are for access, not presentation
Claims control which entries the widget can fetch. They do not replace tenant runtime defaults for presentation, and they do not create a separate anonymous widget mode.
Safe defaults
These habits keep the auth model simple and predictable in production.
- Never expose widget credential secrets in browser code, mobile bundles, or public environment variables.
- Keep widget JWT TTL short. Ten minutes is a good default for logged-in product usage.
- Rotate widget credentials regularly and update the backend secret manager immediately after rotation.
- Only include claims that the widget actually needs to evaluate visibility.
- Handle token minting through your normal app session instead of inventing a second auth flow for the widget.
What to read next