JAVASCRIPT
Securely Receiving and Verifying Webhook Payloads in Node.js
Set up a secure Node.js Express endpoint to receive webhook notifications and verify their authenticity using HMAC signatures, crucial for API integrations.
const express = require('express');
const crypto = require('crypto');
const bodyParser = require('body-parser');
const app = express();
const port = 3000;
const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET; // Ensure this is stored securely
// Use raw body parser for webhook endpoints to get the raw body string
app.post('/webhook', bodyParser.raw({ type: 'application/json' }), (req, res) => {
if (!WEBHOOK_SECRET) {
console.error('WEBHOOK_SECRET not configured.');
return res.status(500).send('Server error: Webhook secret not set.');
}
const signature = req.headers['x-hub-signature'] || req.headers['x-webhook-signature']; // Adjust header name as per provider
if (!signature) {
return res.status(401).send('No signature header provided.');
}
// Convert Buffer to string for HMAC calculation
const payload = req.body.toString('utf8');
const hmac = crypto.createHmac('sha256', WEBHOOK_SECRET);
hmac.update(payload);
const digest = 'sha256=' + hmac.digest('hex'); // Adjust prefix as per provider, e.g., 'v1=' for GitHub
if (digest === signature) {
console.log('Webhook signature verified successfully!');
const event = JSON.parse(payload); // Now parse the payload as JSON
// Process the webhook event here
console.log('Received webhook event:', event.type);
res.status(200).send('Webhook received and processed.');
} else {
console.warn('Webhook signature verification failed!');
res.status(403).send('Invalid webhook signature.');
}
});
app.listen(port, () => {
console.log(`Webhook listener running on http://localhost:${port}`);
});
How it works: This Node.js Express snippet demonstrates how to securely receive and verify webhook payloads. Many API providers send a signature along with the webhook payload, typically in an HTTP header, which is a hash of the payload generated using a shared secret. This code uses `body-parser.raw` to get the raw request body, computes its HMAC signature using `crypto.createHmac`, and compares it with the received signature. This process ensures that the webhook originated from the legitimate source and that its payload has not been tampered with during transit.