Chat Widget
Widget Authentication
Secure the chat widget with magic link session tokens.
Three separate secrets
| Secret | Who issues | Purpose |
|---|---|---|
AELIO_SDK_SECRET | You configure | SDK ↔ Server WebSocket + protected HTTP routes |
| LLM API keys | Provider | Server ↔ LLM provider |
| Session token | Aelio server | Widget ↔ Server WebSocket (per-user, short-lived) |
Never put AELIO_SDK_SECRET in frontend code.
Magic link flow (production)
1. Your backend requests a magic link
curl -X POST https://your-aelio-server.com/auth/magic-link \
-H "Authorization: Bearer $AELIO_SDK_SECRET" \
-H "Content-Type: application/json" \
-d '{"email": "user@example.com", "externalId": "user_abc123"}'Requires Bearer AELIO_SDK_SECRET. Returns a magic link URL.
2. User clicks the link
GET /auth/verify?token=...Returns:
{
"customerId": "user_abc123",
"externalId": "user_abc123",
"email": "user@example.com",
"sessionToken": "eyJ..."
}3. Widget uses the session token
mountAelioChat({
serverUrl: 'https://your-aelio-server.com',
customerId: 'user_abc123',
authToken: sessionToken, // from step 2
email: 'user@example.com',
});Session tokens are HMAC-SHA256 signed, TTL default 60 minutes. The server verifies the token matches customerId to prevent spoofing.
Anonymous mode (development only)
Set in config.yaml:
identity:
allow_anonymous: trueAllows widget init without a token. Not recommended for production.
Development without auth
For local dev, you can pass just customerId and email:
<script
src="http://localhost:3010/widget.js"
data-server-url="http://localhost:3010"
data-customer-id="demo-shopper"
data-email="user@example.com"
></script>Error codes
| Code | Meaning |
|---|---|
auth_required | Token required but not provided |
identity_mismatch | Token doesn't match customerId |
origin_not_allowed | Page origin not in allowlist |