Auth for Chat
Security Best Practices
Keep your implementation secure
Do's
- Generate tokens server-side - Never expose API credentials in frontend code
- Use HTTPS - Always use secure connections in production
- Store customer user IDs - Save
user.idfrom token generation for invalidation - Use shorter expiration times - Set
expiresInto15m-1hfor high-security scenarios - Invalidate on security events - Always invalidate tokens after password resets, permission changes, or suspicious activity
- Store tokens securely - Use httpOnly cookies or secure session storage
- Validate users - Ensure users are authenticated in YOUR system before generating tokens
- Set appropriate permissions - Only grant permissions your users actually need
- Monitor token usage - Track API key usage and invalidation attempts for anomalies
- Rotate API keys - Periodically rotate your API keys
- Use environment variables - Store credentials in environment variables, not code
Don'ts
- Never expose
keySecret- Don't include it in frontend code, logs, or repositories - Don't reuse tokens - Generate fresh tokens for each session
- Don't hardcode credentials - Use environment variables or secure vaults
- Don't skip authentication - Always verify users in your system first
- Don't share tokens between users - Each user should have their own token
- Don't log tokens - Tokens in logs are a security risk
- Don't use test tokens in production - Test endpoint is for development only
- Don't use long expiration times unnecessarily - Default 24h is reasonable, avoid 7d+ unless required
Token Lifecycle
sequenceDiagram
participant User
participant YourApp
participant YourBackend
participant PerformChat
User->>YourApp: Opens chat widget
YourApp->>YourBackend: Request chat token
YourBackend->>YourBackend: Verify user authentication
YourBackend->>PerformChat: POST /rest/v1/auth/token
PerformChat->>PerformChat: Validate API key
PerformChat->>PerformChat: Find/create customer_user
PerformChat->>PerformChat: Generate JWT token
PerformChat-->>YourBackend: Return token
YourBackend-->>YourApp: Return token
YourApp->>PerformChat: Connect with token
PerformChat->>PerformChat: Verify token
PerformChat-->>YourApp: Connection established
Note over User,PerformChat: Token expires after expiresIn period (default: 24h)
User->>YourApp: Continues chatting
YourApp->>PerformChat: Token expired
PerformChat-->>YourApp: 401 Unauthorized
YourApp->>YourBackend: Request new token
YourBackend->>PerformChat: POST /rest/v1/auth/token
PerformChat-->>YourBackend: New token
YourBackend-->>YourApp: New token
YourApp->>PerformChat: Reconnect with new token
Token Validation Process
When a request is made with a JWT token, the following checks are performed:
- JWT signature is valid - Cryptographic verification
- JWT has not expired - Check
expiresIntimestamp - Customer user exists and is active - Database lookup
- Token version matches -
payload.tokenVersion === customer_user.token_version - User belongs to correct company - Company isolation
- Agent is active - Agent status check
If any check fails → 401 Unauthorized
Token Invalidation Strategies
When to Invalidate
Always invalidate tokens in these scenarios:
- Password Reset - User changes password
- Permission Changes - User role or permissions modified
- Account Compromise - Suspicious activity detected
- Logout All Devices - User requests to logout everywhere
- Account Deletion - User account is deleted or deactivated
Example: Invalidation After Password Reset
// After successful password reset
await updateUserPassword(userId, newPassword)
// Invalidate all existing tokens
await fetch('/auth/invalidate-token', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
keyId: process.env.API_KEY_ID,
keySecret: process.env.API_KEY_SECRET,
customerUserId: user.performChatUserId
})
})
// User must login again with new passwordToken Expiration Best Practices
| Use Case | Recommended expiresIn | Reason |
|---|---|---|
| High-security operations | 15m - 30m | Minimize exposure window |
| Standard chat sessions | 1h - 4h | Balance security and UX |
| Long-running integrations | 24h (default) | Reasonable default |
| Trusted environments only | 7d | Use sparingly |
Storage Recommendations
Secure Storage
// Store in your database
await db.users.update({
where: { id: userId },
data: {
performChatToken: token,
performChatUserId: customerUserId, // For invalidation
performChatTokenExpiry: expiresAt
}
})
// Client-side: httpOnly cookie (preferred)
res.cookie('chat_token', token, {
httpOnly: true,
secure: true,
sameSite: 'strict',
maxAge: 24 * 60 * 60 * 1000 // 24 hours
})Insecure Storage
// Never do this
localStorage.setItem('token', token) // Vulnerable to XSS
sessionStorage.setItem('token', token) // Still vulnerable
window.chatToken = token // Exposed globallyMonitoring & Alerts
Set up monitoring for:
- Failed token validation attempts - Possible attack
- Unusual invalidation patterns - Multiple invalidations in short time
- Token generation spikes - Unusual activity
- Expired token usage - Users with expired tokens