DiffHook/Docs
GuidesVerifying Signatures

Verifying Signatures

DiffHook signs every webhook payload so you can verify it came from us and wasn't tampered with.

How it works

Each request includes an X-DiffHook-Signature header containing an HMAC-SHA256 signature of the raw request body, prefixed with sha256=.

X-DiffHook-Signature: sha256=abc123def456...

Your signing secret is available in App → Settings → API Keys.

Verifying in Node.js

const crypto = require('crypto')

function verifySignature(req, secret) {
  const signature = req.headers['x-diffhook-signature']
  const expected = 'sha256=' + crypto
    .createHmac('sha256', secret)
    .update(JSON.stringify(req.body))
    .digest('hex')

  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  )
}

app.post('/webhook', (req, res) => {
  if (!verifySignature(req, process.env.DIFFHOOK_SIGNING_SECRET)) {
    return res.status(401).send('Invalid signature')
  }
  res.status(200).send('OK')
  // process event...
})

Verifying in Python

import hmac, hashlib, json

def verify_signature(body: bytes, signature: str, secret: str) -> bool:
    expected = 'sha256=' + hmac.new(
        secret.encode(),
        body,
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(signature, expected)

Important notes

  • Always use crypto.timingSafeEqual (or equivalent) to prevent timing attacks
  • Compute the signature from the raw bytes of the request body, before JSON parsing
  • If X-DiffHook-Signature is missing, reject the request

Rotating your signing secret

Rotate your signing secret in Settings at any time. After rotation, old signatures will fail — update your deployment before revoking the old secret.