← Back to all snippets
NODEJS

Secure Webhook Signature Verification in Node.js

Ensure webhook integrity and authenticity in your Node.js backend by verifying incoming signatures using HMAC, preventing unauthorized data processing.

const express = require('express');
const crypto = require('crypto');
const bodyParser = require('body-parser');

const app = express();
const WEBHOOK_SECRET = 'your_super_secret_webhook_key'; // Keep this secure!

// Middleware to parse raw body for signature verification
// Must be used BEFORE body-parser.json() or similar, as signature needs raw body
const rawBodyMiddleware = (req, res, next) => {
  let data = '';
  req.setEncoding('utf8');
  req.on('data', chunk => {
    data += chunk;
  });
  req.on('end', () => {
    req.rawBody = data;
    next();
  });
};

app.use(rawBodyMiddleware);
app.use(bodyParser.json()); // Now parse JSON after capturing raw body

// Webhook endpoint
app.post('/webhook', (req, res) => {
  const signature = req.headers['x-webhook-signature'] || req.headers['stripe-signature']; // Example header names
  const payload = req.rawBody; // Use the raw body for verification

  if (!signature || !payload) {
    return res.status(400).send('Missing signature or payload.');
  }

  try {
    // Determine algorithm (e.g., 'sha256' for Stripe, 'sha1' for GitHub)
    // Some providers prefix it, like 'v1=' for Stripe, so you might need to extract.
    const hmac = crypto.createHmac('sha256', WEBHOOK_SECRET);
    hmac.update(payload);
    const expectedSignature = `sha256=${hmac.digest('hex')}`; // Adjust prefix if needed

    // Compare signatures securely using timing-attack resistant comparison
    if (crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expectedSignature))) {
      console.log('Webhook signature verified successfully!');
      // Process your webhook data
      console.log('Webhook data:', req.body);
      res.status(200).send('Webhook received and verified.');
    } else {
      console.warn('Webhook signature verification failed!');
      res.status(401).send('Invalid signature.');
    }
  } catch (error) {
    console.error('Error verifying webhook signature:', error);
    res.status(500).send('Internal server error during verification.');
  }
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Webhook listener running on port ${PORT}`);
});
How it works: This Node.js Express snippet demonstrates how to securely verify incoming webhook signatures. Many external services (like Stripe, GitHub) send a signature header along with the webhook payload, generated using a shared secret and HMAC. This code uses a custom middleware to capture the raw request body (essential for verification), then calculates its own HMAC signature using the `crypto` module. Finally, it compares this computed signature with the one provided in the header using `crypto.timingSafeEqual`, which prevents timing attacks, ensuring the webhook's authenticity and integrity before processing its data.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs