Authentication
User Authentication (is-auth.js)
JWT-based authentication with multiple token sources
Token Sources (Priority Order)
session_id→ Lookup inApiSessioncollectiontokenparameter → Direct JWT token- Query string
token→ URL parameter x-tokenheader → HTTP header
JWT Payload Structure
Decoded JWT Payload:
{
workspace_id: String, // Workspace identifier
account_id: String, // Account identifier
uid: String, // User ID
scope: String, // Space-separated permissions (e.g., "conversation analytics")
assignment: Object // User role assignments
}
Scope Conversion
Input/Output Example:
// Input: "conversation analytics crm"
// Output: ["conversation", "analytics", "crm"]
Authentication Flow
1. Client connects with token
↓
2. Middleware extracts token from query/header
↓
3. If session_id → Lookup ApiSession → Get JWT token
↓
4. Verify JWT with JWT_SECRET
↓
5. Parse scope string to array
↓
6. Attach auth object to socket/request
↓
7. Continue to event handler
Scope Verification (scope.js)
Purpose
Verify user has required permission scope before executing socket events
Implementation
const verifyScope = (data, allowedScopes) => {
try {
let allowed = false;
allowedScopes.forEach(s => {
if (data.auth.scope.includes(s)) allowed = true;
});
if (!allowed) {
return Promise.reject({ errno: 403, message: 'NOT_ENOUGH_SCOPE' });
}
return Promise.resolve();
} catch (error) {
return Promise.reject(error);
}
};
Usage Example
// In event handler
async onMessage(data, callback) {
try {
data = await isAuth(data);
await verifyScope(data, ['conversation']); // Require 'conversation' scope
// Handle message...
} catch (error) {
sendResponse(error, callback);
}
}
Connection-Level Verification
// Applied on namespace connection
io.use(isAuth)
.use(verifyScopeOnConnection(['conversation']))
.on('connect', this.onConnect.bind(this));
Visitor Authentication (is-auth-visitor.js)
Current Status: Development placeholder with hardcoded auth object
Note: This middleware currently returns a static auth object and should be reviewed for production readiness before use in production environments.
Authentication Examples
Socket.IO Client with Token
import io from 'socket.io-client';
const socket = io('http://localhost:4000/v1/conversation', {
transports: ['websocket'],
query: {
token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
},
});
Socket.IO Client with Session ID
const socket = io('http://localhost:4000/v1/conversation', {
transports: ['websocket'],
query: {
session_id: '64abc123def456789',
},
});
Socket.IO Client with Header
const socket = io('http://localhost:4000/v1/conversation', {
transports: ['websocket'],
extraHeaders: {
'x-token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
},
});
Security Best Practices
- Use HTTPS/WSS in Production: Always use secure connections
- Rotate JWT Secrets Regularly: Update JWT_SECRET periodically
- Implement Token Expiration: Set reasonable JWT expiration times
- Validate Token Claims: Always verify workspace_id and account_id
- Rate Limiting: Implement per-user rate limits for events
- IP Whitelisting: Consider IP restrictions for sensitive operations