Encrypted channels
Encrypted channels
Section titled “Encrypted channels”Encrypted channels provide end-to-end encryption for sensitive data. Only authorized clients can decrypt the messages, ensuring that your data remains secure even from Jetsocket.io itself.
Basic usage
Section titled “Basic usage”Client-side subscription
Section titled “Client-side subscription”Encrypted channels are identified by the private-encrypted- prefix:
const jetsocket = new Jetsocket("APP_KEY", { cluster: "APP_CLUSTER", channelAuthorization: { endpoint: "/jetsocket/auth" }});
const encryptedChannel = jetsocket.subscribe("private-encrypted-my-channel");Server-side setup
Section titled “Server-side setup”You need to configure the encryption master key on your server:
const Jetsocket = require("jetsocket");
const jetsocket = new Jetsocket({ appId: "APP_ID", key: "APP_KEY", secret: "APP_SECRET", cluster: "APP_CLUSTER", encryptionMasterKey: "your-32-character-encryption-key"});Encryption key requirements
Section titled “Encryption key requirements”The encryption master key must be:
- 32 characters long (256 bits)
- Consistent across all servers that need to encrypt/decrypt messages
- Secure - generate it randomly and keep it secret
Generating a secure key
Section titled “Generating a secure key”const crypto = require("crypto");
// Generate a random 32-character keyconst encryptionKey = crypto.randomBytes(32).toString("base64");console.log("Encryption key:", encryptionKey);Authorization
Section titled “Authorization”Encrypted channels require the same authorization as private channels:
app.post("/jetsocket/auth", (req, res) => { const socketId = req.body.socket_id; const channel = req.body.channel_name; const user = req.user;
if (canAccessChannel(user, channel)) { const authResponse = jetsocket.authorizeChannel(socketId, channel); res.send(authResponse); } else { res.status(403).send("Forbidden"); }});
function canAccessChannel(user, channel) { // Allow access to encrypted channels if (channel.startsWith("private-encrypted-")) { // Add your authorization logic here return user.hasPermission("encrypted-channels"); } return false;}Sending and receiving messages
Section titled “Sending and receiving messages”Server-side triggering
Section titled “Server-side triggering”// Trigger an encrypted eventjetsocket.trigger("private-encrypted-my-channel", "my-event", { message: "This message is encrypted", timestamp: new Date().toISOString()});Client-side listening
Section titled “Client-side listening”const encryptedChannel = jetsocket.subscribe("private-encrypted-my-channel");
encryptedChannel.bind("my-event", (data) => { console.log("Received encrypted message:", data); // The message is automatically decrypted});Complete example
Section titled “Complete example”Secure messaging application
Section titled “Secure messaging application”<!DOCTYPE html><html><head> <script src="https://js.jetsocket.io/latest/jetsocket-with-encryption.min.js"></script></head><body> <div id="chat-container"> <h2>Secure Chat</h2> <div id="messages"></div> <input type="text" id="message-input" placeholder="Type a secure message..."> <button onclick="sendMessage()">Send</button> </div>
<script> const jetsocket = new Jetsocket("APP_KEY", { cluster: "APP_CLUSTER", channelAuthorization: { endpoint: "/jetsocket/auth" } });
const encryptedChannel = jetsocket.subscribe("private-encrypted-secure-chat"); const messagesDiv = document.getElementById("messages");
// Handle successful subscription encryptedChannel.bind("jetsocket:subscription_succeeded", () => { console.log("Connected to encrypted channel"); addSystemMessage("Connected to secure chat"); });
// Handle subscription errors encryptedChannel.bind("jetsocket:subscription_error", (error) => { console.error("Failed to connect to encrypted channel:", error); addSystemMessage("Failed to connect to secure chat"); });
// Handle encrypted messages encryptedChannel.bind("new-message", (data) => { addMessage(data); });
function addMessage(data) { const messageDiv = document.createElement("div"); messageDiv.className = "message"; messageDiv.innerHTML = ` <strong>${data.username}:</strong> ${data.message} <small>${new Date(data.timestamp).toLocaleTimeString()}</small> `; messagesDiv.appendChild(messageDiv); messagesDiv.scrollTop = messagesDiv.scrollHeight; }
function addSystemMessage(message) { const messageDiv = document.createElement("div"); messageDiv.className = "system-message"; messageDiv.textContent = message; messagesDiv.appendChild(messageDiv); messagesDiv.scrollTop = messagesDiv.scrollHeight; }
function sendMessage() { const input = document.getElementById("message-input"); const message = input.value.trim();
if (message) { // Send to server via AJAX fetch("/send-encrypted-message", { method: "POST", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${getAuthToken()}` }, body: JSON.stringify({ message: message, channel: "private-encrypted-secure-chat" }) });
input.value = ""; } } </script></body></html>Server-side implementation
Section titled “Server-side implementation”const express = require("express");const Jetsocket = require("jetsocket");const crypto = require("crypto");
const app = express();app.use(express.json());
// Your encryption master key (store this securely!)const ENCRYPTION_MASTER_KEY = process.env.ENCRYPTION_MASTER_KEY || crypto.randomBytes(32).toString("base64");
const jetsocket = new Jetsocket({ appId: "APP_ID", key: "APP_KEY", secret: "APP_SECRET", cluster: "APP_CLUSTER", encryptionMasterKey: ENCRYPTION_MASTER_KEY});
// Authorization endpointapp.post("/jetsocket/auth", authenticateUser, (req, res) => { const socketId = req.body.socket_id; const channel = req.body.channel_name; const user = req.user;
if (canAccessChannel(user, channel)) { const authResponse = jetsocket.authorizeChannel(socketId, channel); res.send(authResponse); } else { res.status(403).send("Forbidden"); }});
// Send encrypted messageapp.post("/send-encrypted-message", authenticateUser, async (req, res) => { try { const { message, channel } = req.body; const user = req.user;
// Validate channel is encrypted if (!channel.startsWith("private-encrypted-")) { return res.status(400).json({ error: "Invalid channel type" }); }
// Trigger encrypted event await jetsocket.trigger(channel, "new-message", { user_id: user.id, username: user.username, message: message, timestamp: new Date().toISOString() });
res.json({ success: true }); } catch (error) { console.error("Error sending encrypted message:", error); res.status(500).json({ error: "Failed to send message" }); }});
function canAccessChannel(user, channel) { if (channel.startsWith("private-encrypted-")) { // Add your authorization logic here return user.role === "admin" || user.hasPermission("encrypted-channels"); } return false;}
function authenticateUser(req, res, next) { // Your authentication logic here const token = req.headers.authorization?.split(" ")[1]; if (token) { // Verify token and set req.user req.user = verifyToken(token); next(); } else { res.status(401).send("Unauthorized"); }}
app.listen(3000);Security considerations
Section titled “Security considerations”Key management
Section titled “Key management”- Store keys securely: Use environment variables or secure key management systems
- Rotate keys regularly: Change encryption keys periodically
- Backup keys safely: Ensure you can recover keys if needed
- Limit key access: Only authorized personnel should have access to encryption keys
Channel naming
Section titled “Channel naming”- Use descriptive names: Make channel names indicate their purpose
- Include organization prefix: Use prefixes like
private-encrypted-org-for clarity - Avoid sensitive information: Don’t include sensitive data in channel names
// Good channel names"private-encrypted-financial-data""private-encrypted-medical-records""private-encrypted-legal-documents"
// Bad channel names"private-encrypted-secret-stuff""private-encrypted-12345"Error handling
Section titled “Error handling”encryptedChannel.bind("jetsocket:subscription_error", (error) => { console.error("Encrypted channel error:", error);
if (error.status === 403) { showMessage("Access denied to encrypted channel"); } else if (error.status === 500) { showMessage("Encryption error - please try again"); } else { showMessage("Failed to connect to encrypted channel"); }});Performance considerations
Section titled “Performance considerations”Bundle size
Section titled “Bundle size”Encrypted channels require additional encryption libraries, which increase the bundle size:
// Standard build (smaller)import Jetsocket from 'jetsocket-js';
// Encryption-enabled build (larger)import Jetsocket from 'jetsocket-js/with-encryption';Processing overhead
Section titled “Processing overhead”- Encryption/decryption: Adds computational overhead
- Key management: Requires additional processing
- Network latency: Minimal impact on message delivery
Use cases
Section titled “Use cases”Encrypted channels are perfect for:
- Financial applications: Banking, payments, trading
- Healthcare systems: Medical records, patient data
- Legal applications: Confidential documents, attorney-client communications
- Government systems: Classified information, secure communications
- Enterprise applications: Sensitive business data, trade secrets
Best practices
Section titled “Best practices”Development
Section titled “Development”- Test encryption: Verify encryption/decryption works correctly
- Handle key rotation: Plan for key changes
- Monitor performance: Watch for encryption-related performance issues
- Log appropriately: Don’t log encrypted data
Production
Section titled “Production”- Use strong keys: Generate cryptographically secure keys
- Secure key storage: Use secure key management systems
- Monitor usage: Track encrypted channel usage
- Plan for recovery: Have procedures for key recovery
Next steps
Section titled “Next steps”- Learn about private channels for basic security
- Explore presence channels for user tracking
- Check out authentication for user management
- See security best practices for comprehensive guidance