Documentation / Webhooks

Webhook Security

Secure your webhook endpoints

Webhook Security

Protect your webhook endpoints from unauthorized requests and ensure data integrity.

Signature Verification

All webhooks from WebinOne include a signature header that you should verify:

X-WebinOne-Signature: sha256=abc123...

Verifying Signatures

Compute the HMAC signature using your webhook secret and compare it to the header value:

const crypto = require('crypto');

const verifySignature = (payload, signature, secret) => {
  const hmac = crypto.createHmac('sha256', secret);
  const digest = 'sha256=' + hmac.update(payload).digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(digest)
  );
};

IP Allowlisting

For added security, restrict webhook requests to WebinOne's IP ranges:

  • 52.63.142.0/24
  • 13.236.0.0/16

HTTPS Only

WebinOne only delivers webhooks to HTTPS endpoints. Ensure your endpoint has a valid SSL certificate.

Replay Protection

Each webhook includes a timestamp. Reject requests older than 5 minutes to prevent replay attacks:

const timestamp = request.headers['x-webinone-timestamp'];
const age = Date.now() - parseInt(timestamp);
if (age > 300000) { // 5 minutes
  return res.status(400).send('Request too old');
}

🔒 Security Best Practice

Never process webhook data without verifying the signature. An attacker could forge requests to your endpoint.

Code Examples

// Node.js/Express Webhook Handler
const express = require('express');
const crypto = require('crypto');
const app = express();

app.post('/webhooks/webinone', express.raw({type: 'application/json'}), (req, res) => {
  const signature = req.headers['x-webinone-signature'];
  const timestamp = req.headers['x-webinone-timestamp'];
  const payload = req.body.toString();
  
  // 1. Check timestamp
  const age = Date.now() - parseInt(timestamp);
  if (age > 300000) {
    return res.status(400).send('Request too old');
  }
  
  // 2. Verify signature
  const secret = process.env.WEBHOOK_SECRET;
  const hmac = crypto.createHmac('sha256', secret);
  const expectedSig = 'sha256=' + hmac.update(payload).digest('hex');
  
  if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expectedSig))) {
    return res.status(401).send('Invalid signature');
  }
  
  // 3. Process the webhook
  const event = JSON.parse(payload);
  console.log('Valid webhook received:', event.type);
  
  // Process event...
  
  res.status(200).send('OK');
});