JAVASCRIPT
Verifying Webhook Signatures in Node.js Express
Create a secure webhook endpoint in Node.js Express. This snippet verifies incoming requests using a shared secret signature header to prevent unauthorized access and spoofing.
const express = require('express');
const crypto = require('crypto');
const bodyParser = require('body-parser');
const app = express();
const PORT = 3000;
// IMPORTANT: Your secret key shared with the webhook sender
const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET || 'super_secret_key_123';
// Middleware to parse raw body for signature verification
// Must be placed BEFORE any other body-parsing middleware like express.json()
app.use(bodyParser.raw({ type: 'application/json' }));
// Webhook endpoint
app.post('/webhook', (req, res) => {
const signature = req.headers['x-signature'] || req.headers['stripe-signature']; // Adjust header name as per API
const payload = req.body.toString('utf8'); // The raw body as a string
if (!signature) {
return res.status(400).send('No signature header provided.');
}
// Calculate expected signature using HMAC-SHA256 (common algorithm)
// Adjust algorithm ('sha256', 'sha1', etc.) and encoding ('hex', 'base64') as per API docs
const hmac = crypto.createHmac('sha256', WEBHOOK_SECRET);
hmac.update(payload);
const expectedSignature = hmac.digest('hex');
// Compare signatures securely
const isSignatureValid = crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
if (!isSignatureValid) {
console.warn('Webhook signature verification failed!');
return res.status(403).send('Invalid signature.');
}
// If signature is valid, parse the JSON payload and process the event
let event;
try {
event = JSON.parse(payload); // Now it's safe to parse
} catch (err) {
return res.status(400).send('Invalid JSON payload.');
}
console.log('Webhook received and verified!', event.type);
// Process your webhook event here (e.g., update database, trigger actions)
res.status(200).send('Webhook received and processed.');
});
app.listen(PORT, () => {
console.log(`Webhook server listening on port ${PORT}`);
});
How it works: This Node.js Express snippet demonstrates how to create a secure webhook receiver. It uses `body-parser` to get the raw request body, which is crucial for signature verification. The incoming request's signature (e.g., from `x-signature` header) is compared against a locally computed signature using `crypto.createHmac` and a shared `WEBHOOK_SECRET`. `crypto.timingSafeEqual` is used for a secure comparison to prevent timing attacks. Only if the signatures match is the payload parsed and processed, ensuring the request genuinely originated from the trusted API source.