A webhook arrives with a valid HMAC over its raw bytes. Middleware parses the JSON, changes whitespace and key order, then asks the verifier to authenticate the new serialization. The object is equivalent; the signature is not.

Preserve the signed input

import crypto from "node:crypto";

export function verify(raw, header, secret) {

const [ts, sig] = header.split(",");