Skip to content

Signature Verification

Every webhook delivery includes an x-k42-signature header containing a hex-encoded HMAC-SHA256 signature. You should verify this signature to ensure the payload was sent by K42 and has not been tampered with.

How the Signature Is Computed

The signed message is the concatenation of your callback_url and the raw JSON request body (as a string):

message = callback_url + body

The HMAC-SHA256 is computed using your webhook secret as the key, and the result is hex-encoded.

Verifying in Your Handler

javascript
const crypto = require("crypto");

function verifyWebhook(secret, callback_url, raw_body, signature_header) {
  const message = callback_url + raw_body;
  const expected = crypto
    .createHmac("sha256", secret)
    .update(message)
    .digest("hex");

  return crypto.timingSafeEqual(
    Buffer.from(expected, "hex"),
    Buffer.from(signature_header, "hex")
  );
}

// In your request handler:
const signature = req.headers["x-k42-signature"];
const is_valid = verifyWebhook(
  WEBHOOK_SECRET,
  "https://your-service.com/webhooks/k42",
  raw_body,
  signature
);

if (!is_valid) {
  return res.status(401).send("Invalid signature");
}

Important Notes

  • Use constant-time comparison (e.g. crypto.timingSafeEqual) to prevent timing attacks.
  • The callback_url used in verification must match exactly what you registered when creating the webhook.
  • The raw_body must be the raw request body bytes as a string - do not parse and re-serialize the JSON, as whitespace differences will cause verification to fail.
  • The signature is hex-encoded (lowercase), not base64.