JAVASCRIPT
Processing Incoming Webhooks with Node.js and Express
Learn to set up a Node.js Express server to securely receive and process incoming webhooks, including signature verification for data integrity.
const express = require('express');
const bodyParser = require('body-parser');
const crypto = require('crypto'); // For HMAC verification
const app = express();
const port = 3000;
// IMPORTANT: Use raw body for webhook verification if signature uses it.
// body-parser can parse JSON as buffer if needed:
app.use(bodyParser.json({
verify: (req, res, buf) => {
req.rawBody = buf; // Store raw body for signature verification
}
}));
// Secret key provided by the webhook sender (e.g., Stripe, GitHub)
const WEBHOOK_SECRET = 'your_secret_webhook_key'; // Replace with a strong, secret key from your provider environment variable
app.post('/webhook-endpoint', (req, res) => {
// For providers like Stripe, signature is in headers (e.g., 'stripe-signature')
// For simplicity, let's assume a generic `x-webhook-signature` header and HMAC-SHA256
const signature = req.headers['x-webhook-signature'];
if (!signature || !req.rawBody) {
console.error('Webhook: Missing signature or raw body.');
return res.status(400).send('Webhook Error: Missing signature or body.');
}
try {
const hmac = crypto.createHmac('sha256', WEBHOOK_SECRET);
hmac.update(req.rawBody);
const expectedSignature = hmac.digest('hex');
if (expectedSignature !== signature) {
console.error('Webhook: Signature mismatch!');
return res.status(403).send('Webhook Error: Invalid signature.');
}
// Signature is valid, process the webhook payload
const event = req.body;
console.log('Received valid webhook event:', event.type, event.id);
// Example processing based on event type
if (event.type === 'order.created') {
console.log('New order received:', event.data.orderId);
// Perform actions like updating database, sending notifications, etc.
} else if (event.type === 'payment.succeeded') {
console.log('Payment succeeded for:', event.data.customerId);
}
res.status(200).send('Webhook received successfully.');
} catch (error) {
console.error('Error processing webhook:', error.message);
res.status(500).send('Webhook Error: Internal server error.');
}
});
app.listen(port, () => {
console.log(`Webhook listener running on http://localhost:${port}`);
});
// To test locally, you'll need a tool like ngrok to expose your local server
// to the internet, then configure your webhook provider to send events to
// your ngrok URL + /webhook-endpoint
How it works: This Node.js Express snippet demonstrates how to set up an endpoint to receive and securely process incoming webhooks. It uses `body-parser` to ensure the raw request body is available for signature verification. The core security measure involves calculating an HMAC-SHA256 signature of the raw payload using a shared secret and comparing it against the signature provided in the request header. If signatures match, the webhook is considered authentic and its payload can be safely processed, enabling real-time event-driven communication between services.