Framme

Signing & verification

Every webhook request is signed so you can confirm it genuinely came from Framme. The X-Framme-Signature header carries a hex-encoded HMAC-SHA256 of the raw request body, keyed with your subscription's token. Verify it before trusting the payload.

Verify a payload

Compute the HMAC over the raw body (not a re-serialised object) and compare it to the header using a constant-time check.

import crypto from "node:crypto"

function isValid(rawBody, signature, token) {
  const expected = crypto
    .createHmac("sha256", token)
    .update(rawBody, "utf8")
    .digest("hex")
  const a = Buffer.from(expected)
  const b = Buffer.from(signature || "")
  return a.length === b.length && crypto.timingSafeEqual(a, b)
}

// Express: capture the raw body, then verify
app.post("/framme/webhooks", express.raw({ type: "*/*" }), (req, res) => {
  const ok = isValid(req.body, req.get("X-Framme-Signature"), TOKEN)
  if (!ok) return res.sendStatus(401)
  const event = JSON.parse(req.body.toString("utf8"))
  // …handle event, then:
  res.sendStatus(200)
})
Verify against the raw bytes you received. JSON re-serialisation can change whitespace or key order and break the signature.