JAVASCRIPT
Verify Webhook Signatures in Node.js for Security
Learn to secure your Node.js webhook endpoints by verifying incoming request signatures, ensuring data integrity and preventing unauthorized requests.
const crypto = require('crypto');
// Your secret key for webhook verification (should be stored securely, e.g., environment variable)
const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET || 'your_super_secret_key';
function verifyWebhookSignature(req, res, next) {
const signature = req.headers['x-hub-signature-256'] || req.headers['webhook-signature'];
if (!signature) {
console.warn('Webhook signature missing.');
return res.status(401).send('Unauthorized: Signature missing');
}
// Ensure raw body is available. For Express, use `express.raw({type: '*/*'})` middleware.
const rawBody = req.rawBody;
if (!rawBody) {
console.error('Raw body not available for signature verification.');
return res.status(500).send('Internal Server Error: Raw body missing.');
}
const hmac = crypto.createHmac('sha256', WEBHOOK_SECRET);
const digest = hmac.update(rawBody).digest('hex');
const expectedSignature = `sha256=${digest}`;
if (crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expectedSignature))) {
console.log('Webhook signature verified successfully.');
next();
} else {
console.warn('Webhook signature verification failed.');
return res.status(403).send('Forbidden: Invalid signature');
}
}
// Example Express.js usage:
// const express = require('express');
// const bodyParser = require('body-parser');
// const app = express();
// app.use(bodyParser.json({ verify: (req, res, buf) => { req.rawBody = buf; } })); // Make raw body available
// app.post('/webhook', verifyWebhookSignature, (req, res) => {
// console.log('Received verified webhook payload:', req.body);
// res.status(200).send('Webhook received and processed.');
// });
// app.listen(3000, () => console.log('Server running on port 3000'));
How it works: This Node.js snippet demonstrates how to verify webhook signatures, a critical security measure when receiving data from third-party APIs (e.g., Stripe, GitHub). By comparing a computed hash of the incoming request body with the signature provided in the request headers (using a shared secret key), you can confirm that the webhook originated from a legitimate source and that its payload has not been tampered with during transit. This prevents unauthorized entities from sending forged or malicious data to your endpoints.