Signing users in with JWT
Use a JSON Web Token (JWT) when the page that hosts the widget already knows who the visitor is, for example after SSO or a portal login. Each visitor then gets their own identity in SerenityGPT, and chat history shows only their own conversations.
Use a plain tenant token only when the audience is anonymous and the content is public. Anyone who reads the page source can reuse a tenant token.
How it works
- The SerenityGPT team gives you a signing secret for your installation.
- Your server signs a short-lived token for the signed-in user when it renders the page.
- The page passes the token to the widget in
api_token. SerenityGPT checks the signature and the expiration time on every request.
The secret stays on your server. Only the signed token reaches the browser.
Warning
Anyone who has the secret can sign a token for any user and any tenant on the installation. Store it in your server environment, never in browser code or in source control.
Token claims
| Claim | Required | Description |
|---|---|---|
u |
Yes | Stable user ID, for example portal:8f14e45f. SerenityGPT creates the user on first use. Use an ID that never changes, not an email address: changing u creates a new user without the old history. |
tenant |
Yes | Tenant code the widget is embedded for. The user searches this tenant only. |
exp |
Yes | Expiration time as a Unix timestamp in seconds, not milliseconds. |
metadata |
No | JSON object stored on the user and on each question. Send it only when you need it in reports. |
Sign the token with HS256.
SerenityGPT trusts the u and tenant values in a valid token and gives the user access to that tenant. Your server decides who the user is and what they can search:
- Take
ufrom the signed-in session on your server. Never use an ID or a tenant sent by the browser. - Start
uwith a prefix that is unique to your identity source, followed by an ID that is never reassigned. - Check that the user is allowed to use the tenant before you sign the token.
- Sign tokens for ordinary users only. Accounts with administrator access in SerenityGPT can read every conversation in their tenant.
Signing a token
Python
import os
import time
import jwt # pip install pyjwt
def serenity_token(user_id: str) -> str:
payload = {
"u": f"portal:{user_id}",
"tenant": "support",
"exp": int(time.time()) + 10 * 3600, # 10 hours
}
return jwt.encode(payload, os.environ["SERENITY_JWT_SECRET"], algorithm="HS256")
Node.js
const jwt = require('jsonwebtoken') // npm install jsonwebtoken
function serenityToken(userId) {
return jwt.sign(
{ u: `portal:${userId}`, tenant: 'support' },
process.env.SERENITY_JWT_SECRET,
{ algorithm: 'HS256', expiresIn: '10h' },
)
}
Passing the token to the widget
Render the token into the page from your server:
<script>
var SERENITY_WIDGET = {
api_url: "https://<your-backend-url>/api/v2/",
api_token: "{{ serenity_token }}",
history: true
};
</script>
<script src="https://js.serenitygpt.com/widget.js"></script>
Chat history (history: true) requires a JWT. With a tenant token, the history panel stays hidden.
Calling the API
The API accepts the same token:
Expiration
- Set
exp8 to 12 hours ahead. The widget readsapi_tokenonce when the page loads and does not refresh it. - After
exp, requests fail with401 Token expired. Reloading the page issues a new token. - Signing out of your application does not revoke a token that is already issued. It stays valid until
exp.
Tenant
- Send
tenantin every token. Without it, SerenityGPT uses the user's default tenant, which can be a different content set. - The user cannot switch tenants from the widget. To give a user another tenant, sign a new token with that tenant.
- An unknown tenant code fails with
400 Tenant '<code>' not found.
Errors
| Status | Message | Cause |
|---|---|---|
| 401 | Token expired |
exp is in the past. |
| 401 | Token missing expiration |
No exp claim. |
| 401 | Token missing username |
No u claim. |
| 401 | Invalid token: ... |
Wrong secret, wrong algorithm, or a damaged token. |
| 400 | Tenant '<code>' not found |
The tenant claim does not match a tenant. |
Common mistakes
- Signing tokens in browser code, which exposes the secret.
- Setting
expin milliseconds. - Reusing one token for all visitors, which merges their history into one user.