Authio docs

Widgets

Widget tokens

The bearer credential that gates every @authio/widgets call. Minted from your BFF, scoped to one organization + one origin set, capped at 1 hour, revocable instantly.

What a widget token is

Widget tokens are a third, fully separate JWT-kind alongside the existing customer-tenant and platform-tenant JWTs. They embed the organization the widget reads/writes, the scope of operations the widget is allowed to perform (today, sso_connection and/or directory_sync), and the HTTPS origin(s) the token may be presented from.

For the full security posture (origin enforcement, scope checks, DB-row-backed revocation, audit emission) see Widgets security model.

Mint — POST /v1/widget-tokens

Server-only. Caller must be an owner or admin of the org or the tenant; member / viewer get 403 insufficient_role. The endpoint clamps ttl_seconds to [60, 3600] (default 1800 s / 30 minutes).

curl -X POST https://api.authio.com/v1/widget-tokens \
  -H "authorization: Bearer $AUTHIO_DASHBOARD_SESSION_JWT" \
  -H "x-authio-tenant: ten_acme" \
  -H "content-type: application/json" \
  -d '{
    "organization_id": "org_acme_hq",
    "scope":           ["sso_connection", "directory_sync"],
    "origins":         ["https://app.acme.com"],
    "ttl_seconds":     1800
  }'

Response (the JWT is shown once):

{
  "id":         "wtok_a1b2c3d4e5f60718293040ab",
  "token":      "eyJhbGciOi…",
  "expires_at": "2026-05-23T22:00:00Z",
  "warning":    "This token is shown once. Store it server-side and ship it to the browser only at render time."
}

List — GET /v1/widget-tokens

curl "https://api.authio.com/v1/widget-tokens?organization_id=org_acme_hq" \
  -H "authorization: Bearer $AUTHIO_DASHBOARD_SESSION_JWT" \
  -H "x-authio-tenant: ten_acme"

Returns the active, non-expired, non-revoked tokens. Pass ?include_revoked=true to read the full audit history for the org.

Revoke — DELETE /v1/widget-tokens/:id

curl -X DELETE https://api.authio.com/v1/widget-tokens/wtok_a1b2c3d4e5f60718293040ab \
  -H "authorization: Bearer $AUTHIO_DASHBOARD_SESSION_JWT" \
  -H "x-authio-tenant: ten_acme"

Sets revoked_at = now(). The next /widget/* request that presents the JWT returns 401 widget_token_revoked within milliseconds — the guard reads the DB row on every call, not just at JWT-mint.

Revocation is permanent. There is no “un-revoke” action; mint a fresh token if you need one.

Verifying a widget token in your own backend

Widget tokens are intended to be presented by the browser to auth-api.authio.com/widget/* directly — the @authio/widgets bundle handles the wire format and the origin header for you. If you want to verify the JWT yourself (for instance to gate a server-side rendered dashboard panel), use the standard JWKS verifier from @authio/node:

import { JwtVerifier } from "@authio/node";

const verifier = new JwtVerifier({
  jwksUri: "https://auth-api.authio.com/.well-known/jwks.json",
  issuer:  "https://auth-api.authio.com",
});

const claims = await verifier.verify(widgetJwt);
if (claims.kind !== "widget") {
  throw new Error("not a widget token");
}
// claims.tenant_id, claims.organization_id, claims.widget_scope[],
// claims.widget_origins[] are all populated.
Widget JWTs cannot be presented to /v1/sessions/*, /v1/me, or /v1/session/*. Every other Authio surface refuses kind=widget with 403 widget_token_not_allowed_here. Conversely a regular customer-session JWT cannot be presented to /widget/* — it returns 403 widget_token_required.

Read next