Customer authentication
Website auto login
Choose exactly one customer login method in Widget settings: Supportly email codes or Website auto login. Existing and free workspaces use email codes. Guest settings remain separate and apply only where email-code mode and the plan permit.
Backend and browser contract
Website auto login requires a paid, active workspace and a signed-in website account. Logged-out customers see “Sign in to this website to access support.” Backend errors show retry and never switch to Supportly email codes.
The authorized website backend asserts the account email. Supportly cannot independently prove email ownership while skipping verification. Match normalized email within one workspace to share existing history; an email change creates a different customer identity. A website assertion cannot access another workspace or grant dashboard/platform privileges.
Keep the public_widget key in your embed. Create a server_identity key in Settings → API keys; save it once in a private server environment variable. Private keys use 32 random bytes, default to a 1-year expiry, with shorter presets, custom days or an explicit No expiry (dangerous) option, and allow at most 10 active keys per workspace. Rotating a key immediately revokes the old key and its subsequent customer access.
Your backend calls POST /api/widget/auth/server-session with a private Bearer key and application/json. Required fields: email (server account email, max 320 characters), widgetKeyId (public widget key UUID), origin (exact verified allowed origin, max 2,048 characters). Optional customerName is limited to 100 characters. Unknown fields are rejected and the body is limited to 8 KiB. Workspace, plan and key environment are derived from trusted records.
The uncached success envelope is { success: true, data: { sessionToken, expiresAt } }. The session lasts up to 15 minutes (capped by key expiry) and no OTP is sent. This endpoint is backend-only, has no browser CORS support, and rejects browser Origin, Sec-Fetch-Site and Cookie headers. Never forward browser headers from the website request. Node backend fetch metadata is supported.
Implement a same-origin website endpoint that authenticates the website account from the server session. For POST, validate your site's exact Origin and its CSRF token. Do not accept a browser-selected customer email, workspace, plan or widget origin. Use the application's existing secure session and CSRF framework; Supportly cannot enforce CSRF protection inside your website.
Browser integration without credential values
1// Define this before loading widget.js. The website supplies its own CSRF implementation.2window.SupportlyWidgetConfig = {3 async getCustomerSession() {4 const response = await fetch("/support/customer-session", {5 method: "POST", credentials: "same-origin", cache: "no-store",6 headers: { "X-CSRF-Token": getWebsiteCsrfToken() },7 signal: AbortSignal.timeout(15000)8 });9 if (response.status === 401) return null; // Website account is signed out.10 if (!response.ok) throw new Error("Support account unavailable");11 const body = await response.json();12 return body.sessionToken; // Website endpoint unwraps Supportly's data envelope.13 }14};15// Load widget.js with YOUR_PUBLIC_WIDGET_KEY; never put a private key here.1617// Before website logout or account switching:18try {19 await window.SupportlyWidget?.resetIdentity();20} catch {21 // Local support state is cleared; schedule bounded revocation retry.22 scheduleSupportResetRetry(); // Your website's retry implementation.23} finally {24 await signOutOfWebsite(); // Always complete the website's own logout.25}2627// After website sign-in or switching accounts:28await window.SupportlyWidget?.refreshIdentity();The widget calls POST /api/widget/auth/identify with the customer Bearer token, x-api-key public key and x-widget-bootstrap token. Supportly checks customer ownership, public widget key, origin, bootstrap and current policy before history is displayed. Website-issued tokens remain in memory. The widget renews one minute before expiry and resumes the existing conversation only after confirming the same customer.
A null callback shows website sign-in. Callback errors show retry with bounded jittered backoff. Email is never collected in website mode; the supplied name is prefilled and other required pre-chat fields remain required.
Always call resetIdentity on website logout, before changing accounts or removing customer access from your page. Reset clears local customer/history/resume state synchronously, disconnects transport, ignores stale callbacks, and requests revocation of the current session. If logout cannot reach Supportly, local state is cleared but server revocation is not confirmed: retry logout from your integration; the short server expiry remains the upper bound. Same-origin tabs receive the reset notification and clear/revoke their own widget sessions.
Private-key rotation/revocation/expiry, session expiry, domain withdrawal, a customer-login-method change, downgrade or workspace suspension stop subsequent access. HTTP, WebSocket actions and customer delivery recheck live authority. Transport expiry cannot exceed the parent customer session expiry. Guest resume capabilities never authorize account history.
Build your integration prompt
Choose a guided setup or edit every option yourself.
Limits and operations
W is the validated workspace widget RPM allowance (paid defaults 300/1,000/5,000). Keys, sessions and distributed IPs do not increase workspace capacity. Issuance uses separate IP buckets from browser requests. Responses use 429 with Retry-After and rate-limit headers; unavailable authentication/limiter storage fails closed with 503. Use bounded backoff with jitter and respect Retry-After in the website backend.
| Boundary | Allowance |
|---|---|
| Backend issuance before key validation | 6,000/minute and 1,000/10 seconds per trusted IP |
| Invalid private credentials | 30/minute per trusted IP |
| Authenticated issuance | W/minute per workspace and key; workspace burst max(10, ceil(W/6))/10 seconds |
| One normalized-email customer | 6/minute and 30/hour in the workspace |
| Browser identify | 20/minute per trusted IP, 10/minute per customer session, W/minute per workspace |
| Active website sessions | 10 per customer/widget/origin tuple |
| Customer chat writes | 20/minute across HTTP/WebSocket and sessions, plus workspace and AI quotas |
| New customer conversations | 5/minute per customer, plus workspace limits |
Configure TRUSTED_CLIENT_IP_HEADER only for an ingress that overwrites that header and prevents direct origin access. Never trust arbitrary client X-Forwarded-For. Without a configured trusted ingress, clients intentionally share the unknown bucket. Enforce ingress body-read timeouts, header size and connection limits alongside the application body/payload limits.
Deployment operators can disable issuance globally with SUPPORTLY_IDENTITY_ISSUANCE_DISABLED=true, set workspaces.identity_issuance_disabled for one workspace, or set workspaces.suspended_at to stop all customer access. These controls require operator database/deployment access, not website keys. Revocation, cleanup and existing email-code mode remain available when issuance is disabled. Run indexed, bounded security maintenance regularly and monitor the redacted supportly_identity metrics, denial rates, refresh failures, latency and retained storage.