Chatbot Authentication
Chatbot authentication lets you tie widget conversations to known customers using JSON Web Tokens (JWTs). When enabled, verified users see their full conversation history across sessions, and any custom claims you include in the token become available as agent context.
Prerequisites
- Enable Strict Authentication in Agent Settings → Security.
- Copy your secret key from the same page — click the eye icon to reveal it, then copy.
1. Generate a JWT (server-side)
Sign a JWT on your backend using HS256 and your secret key. Never expose the secret key in client-side code.
Required claim:
| Claim | Description |
|---|---|
sub | A stable customer identifier (e.g. user ID, email) |
Recommended claim:
| Claim | Description |
|---|---|
exp | Token expiry — keep it short (e.g. 1 hour) |
Any custom claims beyond the reserved set (iat, exp, nbf, iss, aud, jti, sub) are automatically passed to the agent as conversation context.
Node.js example
const jwt = require('jsonwebtoken');
const token = jwt.sign(
{
sub: user.id,
email: user.email,
plan: user.plan, // custom claim → agent context
orderId: order.id, // custom claim → agent context
},
process.env.APPLIED_SECRET_KEY,
{ expiresIn: '1h' }
);Python example
import jwt
import time
token = jwt.encode(
{
"sub": user.id,
"email": user.email,
"plan": user.plan, # custom claim → agent context
"orderId": order.id, # custom claim → agent context
"exp": int(time.time()) + 3600,
},
os.environ["APPLIED_SECRET_KEY"],
algorithm="HS256",
)2. Pass the token to the widget
Set the contact-context-token HTML attribute when rendering the widget:
<applied-chat-widget
agent-id="your-agent-id"
contact-context-token="YOUR_JWT"
></applied-chat-widget>When a user logs in or their identity changes, re-render the widget element with the new token value.
3. Logout
Call logout() to clear the session and revoke the token. The widget resets to an anonymous state.
window.applied.logout();4. Conversation history visibility
| User type | History |
|---|---|
Verified (valid JWT with sub) | Full history across all sessions |
| Anonymous (no JWT) | Current session only |
How metadata works with authentication
When a verified identity is active (contact-context-token JWT, Shopify proxy auth, or strict auth mode), the server strips metadata.context and metadata.groups from requests and replaces them with the verified claims from the JWT.
This means any metadata.context fields (firstName, email, etc.) and metadata.groups in the HTML attribute are ignored when a verified identity is active — the JWT is the sole source of identity. Other metadata keys (data, source, platform, state, etc.) are still passed through normally.
<!-- context and groups are stripped server-side when a verified identity is active; data is sent as-is -->
<applied-chat-widget
agent-id="your-agent-id"
contact-context-token="YOUR_JWT"
metadata='{"context":{"firstName":"Ignored"},"data":{"orderId":"12345"}}'
></applied-chat-widget>Consistent claims across sites
If your chatbot is embedded on multiple sites (e.g. a marketing site and an app), use the same JWT claims across all of them.
Different claims on different sites can cause unexpected behavior if a user has multiple tabs open, since sessions and contacts are shared across origins. For example, if Site A signs a token with {firstName: "Chris"} and Site B signs with {firstName: "Christina"}, the contact record may flip between values depending on which tab re-initializes last.
Security best practices
- Never expose your secret key in client-side code. Always generate tokens on your server.
- Always set
expto limit the window of a compromised token. - Rotate your secret key immediately if it is ever exposed.
- Use HTTPS for all pages embedding the widget.
See also
- Chat Widget Setup — embedding and configuration
- Chatbot Styling — visual customization