JAVASCRIPT

Enhancing Webhook Security: Verifying Signatures in Node.js

Learn to implement webhook signature verification in Node.js to ensure incoming webhook payloads are authentic and untampered, improving API security.

const express = require('express');
const crypto = require('crypto');
const bodyParser = require('body-parser'); // For raw body access

const app = express();
const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET || 'your_super_secret_key_here'; // Use environment variable!

// IMPORTANT: body-parser must be configured to parse raw body
// This allows us to access req.rawBody which is crucial for signature verification.
app.use(bodyParser.json({
  verify: (req, res, buf) => {
    req.rawBody = buf; // Store the raw body buffer
  },
}));

// Example webhook endpoint
app.post('/webhook', (req, res) => {
  const signature = req.headers['x-hub-signature-256'] || req.headers['x-webhook-signature']; // Check your provider's header name

  if (!signature) {
    console.warn('Webhook received without signature.');
    return res.status(401).send('Unauthorized: No signature provided.');
  }

  // Recreate the expected signature
  // The hash algorithm (sha256) and encoding (hex) depend on the provider.
  const hmac = crypto.createHmac('sha256', WEBHOOK_SECRET);
  hmac.update(req.rawBody);
  const expectedSignature = `sha256=${hmac.digest('hex')}`; // Match format, e.g., 'sha256=' prefix

  // Compare signatures
  // Using crypto.timingSafeEqual to prevent timing attacks
  const isSignatureValid = crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expectedSignature));

  if (!isSignatureValid) {
    console.warn('Webhook received with invalid signature.');
    return res.status(403).send('Forbidden: Invalid signature.');
  }

  // Signature is valid, process the webhook payload
  console.log('Webhook payload verified:', req.body);
  res.status(200).send('Webhook received and verified.');
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Server listening on port ${PORT}`);
  console.log('Webhook Secret:', WEBHOOK_SECRET); // For development, do NOT log in production
});
How it works: This Node.js snippet demonstrates how to securely verify the signature of incoming webhook payloads. Many API providers send a signature (often a hash of the payload) in a request header to allow recipients to confirm the authenticity and integrity of the data. This code uses Node.js's `crypto` module to generate an HMAC hash of the raw request body using a shared secret and then compares it with the signature provided in the header. Utilizing `bodyParser` with a `verify` function is crucial to access the raw request body, and `crypto.timingSafeEqual` is used for a secure comparison to prevent timing attacks.

Need help integrating this into your project?

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

Hire DigitalCodeLabs