JAVASCRIPT

Securing Webhooks by Verifying Request Signatures

Implement robust security for your webhook endpoints by verifying the request signature using a shared secret, protecting against unauthorized or tampered payloads.

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

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

// Middleware to parse raw body for signature verification
app.use(bodyParser.raw({ type: 'application/json' }));

app.post('/webhook', (req, res) => {
  const signature = req.headers['x-webhook-signature']; // Or 'x-hub-signature', etc.
  const payload = req.body.toString('utf8'); // Get raw body as string

  if (!signature) {
    return res.status(401).send('No signature header provided.');
  }

  // Calculate expected signature
  const hmac = crypto.createHmac('sha256', WEBHOOK_SECRET);
  hmac.update(payload);
  const expectedSignature = `sha256=${hmac.digest('hex')}`;

  if (crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expectedSignature))) {
    // Signature is valid! Process the webhook payload.
    const event = JSON.parse(payload); // Parse the payload now
    console.log('Webhook received and verified:', event.type);
    res.status(200).send('Webhook received and processed.');
  } else {
    console.warn('Webhook signature verification failed!');
    res.status(403).send('Invalid signature.');
  }
});

// app.listen(3000, () => console.log('Webhook server listening on port 3000'));
How it works: This Node.js Express snippet demonstrates how to secure a webhook endpoint by verifying the request signature. It uses the `crypto` module to calculate an HMAC (Hash-based Message Authentication Code) of the raw request body using a shared secret key. This calculated signature is then compared with the signature provided in a special HTTP header (e.g., `X-Webhook-Signature`). If they match, the webhook request is deemed authentic and untampered; otherwise, it's rejected, protecting your application from malicious or spoofed payloads. Note the use of `bodyParser.raw` to get the raw body before parsing, which is essential for signature verification.

Need help integrating this into your project?

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

Hire DigitalCodeLabs