Embed Widgets: Authentication
Three auth modes — anonymous, bridge token, magic link — with full code samples for Node.js, Python, and Go. Choose the right mode for your portal.
Which mode should I use?#
The plugin tier supports three authentication modes. Pick the one that matches your portal's existing auth setup:
Anonymous mode#
The simplest mode. Drop a PricingCard with just tenantSlug and embedKey. No backend changes needed.
Anonymous mode is enforced server-side: the headless config endpoint only returns offerings marked PUBLISHED, and the embed key's domain allowlist must include the requesting page's origin.
Bridge token mode#
For widgets that need to know which customer the page belongs to. Your backend mints a short-lived signed token; the widget exchanges it for an in-memory session JWT. Your signing key never reaches the browser.
Step 1 — Get your signing key
In Embed Studio, navigate to Auth Bridge, click Mint a new signing key, and choose HS256 or RS256. Store the key material in your secret manager (HSM, KMS, Vault). Never commit it to source.
Step 2 — Mint bridge tokens on your backend
Bridge tokens are short-lived (5 minutes recommended) JWTs signed with your key. The payload carries the customer identity Aforo should associate with this session.
Step 3 — Pass the token to your widget
Step 4 — Aforo exchanges the bridge token for a session JWT
On mount, the widget calls AforoSession.init({ tenantSlug, embedKey, bridgeToken }) and then awaits AforoSession.getSessionJwt(tenantSlug), which POSTs to Aforo's bridge endpoint. Aforo verifies the signature against the registered public key (RS256) or shared secret (HS256), maps your external_customer_id to an internal Aforo customer (creating one on first sight), and returns a session JWT bound to that customer + workspace.
The session JWT lives in memory only — never in localStorage, never in cookies. It expires after 1 hour and is auto-refreshed 5 minutes before expiry. If your customer changes (e.g. logout/login), call AforoSession.destroy(tenantSlug) and remount the widget to start a fresh exchange.
Magic link mode#
For portals that don't have their own session yet. The customer types their email, gets an Aforo-branded email, clicks the link, and lands back on your page with a session JWT. Aforo handles the entire flow — your backend doesn't need to mint anything.
On mount, the widget renders an email input. After the customer submits, they see a Check your inbox confirmation. The link in the email returns the customer to the same page with ?aforo_magic_token=… in the URL — the SDK detects it, exchanges it for a session JWT, and renders the actual invoice list. The URL parameter is stripped via history.replaceState so it doesn't end up in the page's analytics.
Anti-enumeration posture
The magic-link request endpoint always returns the same 202 Accepted envelope regardless of whether the email is registered. Attackers cannot use it as a user-registration probe.
Rate limits
- Per IP — 10 magic-link requests per minute. Excess requests get a silent 202 (no error, but no email sent).
- Per email — 5 magic-link requests per hour. Same silent 202 behavior past the cap.
- Token validity — 15 minutes, one-time use, pessimistic-lock enforced server-side so the same link cannot be redeemed twice even if the customer clicks fast.
Security boundaries#
See the for the full security model, CSP guidance, and how to report vulnerabilities.