Implementation Examples
This page walks through a complete Node.js webhook server that includes IP whitelisting, HMAC signature verification, security headers, and payload processing.
Prerequisites
- Node.js 18.0.0 or later
- A webhook shared secret from the eCourtDate Console
Project Setup
mkdir ecd-webhook-demo && cd ecd-webhook-demo
npm init -y
touch config.js app.js
Configuration
config.js
module.exports = {
port: process.env.PORT || 3000,
webhookSecret: process.env.WEBHOOK_SECRET || 'your-webhook-secret-here',
allowedIPs: [
// Add eCourtDate webhook IPs from Console
],
};
Server
app.js
const http = require('http');
const crypto = require('crypto');
const config = require('./config');
const server = http.createServer((req, res) => {
// Security headers
res.setHeader('Content-Security-Policy', "default-src 'none'");
res.setHeader('X-Content-Type-Options', 'nosniff');
res.setHeader('X-Frame-Options', 'DENY');
res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
if (req.method !== 'POST' || req.url !== '/webhook') {
res.writeHead(404);
return res.end('Not Found');
}
// IP validation
const clientIP = req.headers['x-forwarded-for']?.split(',')[0]?.trim()
|| req.socket.remoteAddress;
if (config.allowedIPs.length > 0 && !config.allowedIPs.includes(clientIP)) {
res.writeHead(403);
return res.end('Forbidden');
}
let body = '';
req.on('data', (chunk) => {
body += chunk;
if (body.length > 1e6) req.destroy(); // 1MB limit
});
req.on('end', () => {
// Verify signature
const signature = req.headers['x-ecd-signature'];
if (signature) {
const expected = crypto
.createHmac('sha256', config.webhookSecret)
.update(body)
.digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) {
res.writeHead(401);
return res.end('Invalid signature');
}
}
try {
const event = JSON.parse(body);
console.log('Webhook received:', event.uuid, event.channel, event.direction);
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ received: true, timestamp: new Date().toISOString() }));
} catch (err) {
res.writeHead(400);
res.end('Invalid JSON');
}
});
});
server.listen(config.port, () => {
console.log(`Webhook server listening on port ${config.port}`);
});
Running the Server
node app.js
The server starts on port 3000 by default and listens for POST requests at /webhook.
Production Recommendations
- Use HTTPS -- terminate TLS via a reverse proxy (nginx, Caddy) or the Node.js
httpsmodule - Process manager -- deploy with PM2 or systemd to handle restarts and clustering
- Logging and monitoring -- implement structured logging and alerting for failed verifications or errors
- IP allowlist -- update the
allowedIPsarray inconfig.jswith the actual production IPs listed in the Console - Environment variables -- set
WEBHOOK_SECRETvia an environment variable rather than hardcoding it in the config file
Next Steps
- Troubleshooting -- diagnose common integration issues
- Security -- review all security recommendations