Thursday, October 16, 2025

๐Ÿ“ฆ From Payload to Proof: Verifying Webhooks with Crypto ๐Ÿ” + Node.js ⚙️

๐Ÿ” Webhook HMAC Verification Guide

๐Ÿ” Webhook Listener: HMAC Verification Guide

Secure your civic endpoints with HMAC SHA256 verification and audit-grade secrets…

To ensure incoming webhook requests are authentic and untampered, the listener uses HMAC SHA256 verification with a shared secret (WEBHOOK_SECRET or GITHUB_WEBHOOK_SECRET).

HMAC verification is your first line of defense against spoofed or malicious webhook traffic.

๐Ÿงญ Step-by-Step Setup

  1. Generate a Secure Secret
    Use OpenSSL or any cryptographic tool:
    openssl rand -hex 32
    Example output:
    civic-rotator-override-9f3a7c2e1b6d4a8f3c1e2a7d9b5f6c3e
  2. Set Environment Variables
    In .env or Vercel dashboard:
    WEBHOOK_SECRET=civic-rotator-override-9f3a7c2e1b6d4a8f3c1e2a7d9b5f6c3e GITHUB_WEBHOOK_SECRET=your-github-secret
  3. Reference in Listener Code
    const secret = process.env.WEBHOOK_SECRET;

๐Ÿงช Example: HMAC Verification in api/webhook-listener.js

import crypto from 'crypto'; export default async function handler(req, res) { const signature = req.headers['x-signature'] || ''; const rawBody = JSON.stringify(req.body); const secret = process.env.WEBHOOK_SECRET; const hmac = crypto.createHmac('sha256', secret).update(rawBody).digest('hex'); const isValid = crypto.timingSafeEqual(Buffer.from(hmac), Buffer.from(signature)); if (!isValid) { return res.status(401).json({ error: 'Invalid signature' }); } res.status(200).json({ status: 'Webhook verified', received: req.body }); }

⚠️ Common Issues & Fixes

IssueCause / Fix
Invalid signatureSignature header missing or incorrect secret used
crypto.timingSafeEqual failsBuffer mismatch—ensure both values are hex strings of equal length
undefined process.env.SECRETEnvironment variable not set or misnamed in Vercel
rawBody is emptyUse middleware to capture raw body before parsing
๐Ÿงฉ GitHub-Specific Notes:
Use the x-hub-signature-256 header and compute HMAC using:
crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
Strip the sha256= prefix before comparing.

No comments:

Post a Comment

๐Ÿ“Š The immortal Executive Dashboard That Gives You "God" Level Visibility: From Data Overload to Clarity: How This Dashboard Simplifies Your Decisions

Executive Dashboard | HealthTrend Cognitive Platform ๐Ÿง  HEALTHTREND COGNITIVE ...