Verifying the signature
This section is for your developer.
Anyone who knows your URL could post to it. Checking the signature proves a message came from your store.
How it's made
X-Trooply-Signature = sha256= + the lowercase hex HMAC-SHA256 of the raw request body, using the webhook's Signing Secret (as plain text) as the key.
Three things to get right:
- Sign the raw body bytes exactly as received. Don't parse and re-serialise the JSON first.
- Use the secret as text; don't decode it from hex.
- Include the
sha256=prefix when comparing.
Example (Node.js)
const crypto = require("crypto");
app.post("/hooks/store", express.raw({ type: "application/json" }), (req, res) => {
const expected = "sha256=" + crypto
.createHmac("sha256", process.env.WEBHOOK_SECRET)
.update(req.body)
.digest("hex");
const got = req.get("X-Trooply-Signature") || "";
if (got.length !== expected.length ||
!crypto.timingSafeEqual(Buffer.from(got), Buffer.from(expected))) {
return res.status(401).send("bad signature");
}
const event = JSON.parse(req.body.toString("utf8"));
// handle event.event / event.payload
res.json({ ok: true });
});
Example (Python)
import hmac, hashlib
def verify(raw_body: bytes, header: str, secret: str) -> bool:
expected = "sha256=" + hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, header or "")
Lost the secret? Delete the webhook and create a new one; a new secret is generated.
