Webhook: verifying the signature
Reference for web developers. Use HMAC-SHA256 and the signing secret to check that a webhook message really comes from meetpiloot and is not stale.
PlusFor developers1 min read
On this page1
Every message carries the header X-Meetpiloot-Signature: sha256= followed by an HMAC-SHA256 over the exact body, with your signing secret as the key. Recompute it over the raw body and compare using a timing-safe function.
X-Meetpiloot-Timestamp holds the time the message was sent, in ISO 8601. Reject messages older than a few minutes, so an intercepted message cannot be replayed later.
Example in Node.js (Express)
JavaScript
const crypto = require('crypto');
function isFromMeetpiloot(rawBody, header, secret) {
const expected =
'sha256=' + crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
const a = Buffer.from(header || '');
const b = Buffer.from(expected);
// timingSafeEqual throws on unequal lengths, so check that first.
if (a.length !== b.length) return false;
return crypto.timingSafeEqual(a, b);
}
// Note express.raw(): the signature covers the exact bytes we sent,
// so verify before you parse or re-serialise the JSON.
app.post('/meetpiloot', express.raw({ type: 'application/json' }), (req, res) => {
if (!isFromMeetpiloot(req.body, req.get('X-Meetpiloot-Signature'), process.env.MP_SECRET)) {
return res.sendStatus(401);
}
const payload = JSON.parse(req.body.toString('utf8'));
if (payload.event === 'lead.test') return res.sendStatus(200); // a test, not a real lead
res.sendStatus(200); // reply first...
forwardToCrm(payload); // ...then do the slow work
});Read next
Stuck?
Email us or open a ticket from your dashboard. We reply within 1 to 2 working days.