Skip to main content
Documentation

Verifying webhook signatures

Every outbound webhook from Veyra carries a Veyragate-Signature header. Verify it before trusting the payload — code samples in 7 languages below.

import crypto from "node:crypto";

const TOLERANCE_SECONDS = 300;

export function verifyVeyragateSignature(
  rawBody: string,
  header: string | null | undefined,
  secret: string,
  now = Math.floor(Date.now() / 1000),
): boolean {
  if (!header) return false;
  const parts = Object.fromEntries(
    header.split(",").map((p) => p.trim().split("=", 2) as [string, string]),
  );
  const t = parseInt(parts.t, 10);
  const v1 = parts.v1;
  if (!t || !v1) return false;
  if (Math.abs(now - t) > TOLERANCE_SECONDS) return false;
  const expected = crypto
    .createHmac("sha256", secret)
    .update(`${t}.${rawBody}`)
    .digest("hex");
  return crypto.timingSafeEqual(
    Buffer.from(expected, "utf8"),
    Buffer.from(v1, "utf8"),
  );
}
Each snippet enforces a 5-minute timestamp tolerance, parses the t= and v1= fields from the Veyragate-Signature header, and uses constant-time comparison to defeat timing attacks.