JAVASCRIPT

Secure Webhook Processing with Signature Verification (Node.js)

Ensure the integrity and authenticity of incoming webhook payloads by verifying request signatures using a shared secret, protecting against malicious spoofing.

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

const app = express();
const WEBHOOK_SECRET = 'your-super-secret-key'; // Store this securely, e.g., in environment variables

// Use raw body parser for webhook requests as we need the raw body for signature verification
app.use(bodyParser.json({
  verify: (req, res, buf) => {
    // Store the raw body so we can access it later for verification
    req.rawBody = buf.toString();
  }
}));

app.post('/webhook', (req, res) => {
  const signature = req.headers['x-hub-signature-256'] || req.headers['x-hub-signature']; // Example header
  const payload = req.rawBody;

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

  // Example for GitHub-style signature (HMAC SHA256)
  // Format: 'sha256=<signature>'
  const [algo, hash] = signature.split('=');
  if (algo !== 'sha256') { // Or 'sha1' depending on the service
    console.warn('Unsupported signature algorithm:', algo);
    return res.status(400).send('Bad Request: Unsupported signature algorithm.');
  }

  const hmac = crypto.createHmac(algo, WEBHOOK_SECRET);
  hmac.update(payload);
  const digest = hmac.digest('hex');

  if (crypto.timingSafeEqual(Buffer.from(digest), Buffer.from(hash))) {
    console.log('Webhook signature verified successfully!');
    // Process the webhook payload (req.body contains the parsed JSON)
    console.log('Webhook payload:', req.body);
    res.status(200).send('Webhook received and processed.');
  } else {
    console.error('Webhook signature verification failed!');
    res.status(403).send('Forbidden: Invalid signature.');
  }
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Webhook server listening on port ${PORT}`);
});
How it works: This Node.js Express snippet demonstrates how to verify incoming webhook requests using a shared secret. It uses `body-parser` to get the raw request body, which is essential for signature calculation. The `crypto` module then computes an HMAC hash of the payload using a secret key and compares it securely with the signature provided in the request headers, ensuring the webhook's authenticity and integrity.

Need help integrating this into your project?

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

Hire DigitalCodeLabs