Verify webhook signatures
- TypeScript
- Python
- Go
- cURL
import { createHmac, timingSafeEqual } from "node:crypto";
function verifyWebhook(payload: string, signature: string, secret: string): boolean {
const expected = createHmac("sha256", secret).update(payload).digest("hex");
const left = Buffer.from(`sha256=${expected}`);
const right = Buffer.from(signature ?? "");
if (left.length !== right.length) return false;
return timingSafeEqual(left, right);
}
import hashlib
import hmac
def verify_webhook(payload: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(secret.encode("utf-8"), payload, hashlib.sha256).hexdigest()
return hmac.compare_digest(f"sha256={expected}", signature or "")
func VerifyWebhook(payload []byte, signature string, secret string) bool {
mac := hmac.New(sha256.New, []byte(secret))
mac.Write(payload)
expected := "sha256=" + hex.EncodeToString(mac.Sum(nil))
return hmac.Equal([]byte(expected), []byte(signature))
}
payload='{"type":"checkout.paid","data":{"checkoutId":"cs_123"}}'
signature=$(printf '%s' "$payload" | openssl dgst -sha256 -hmac "$ACCEND_WEBHOOK_SECRET" -hex | sed 's/^.* /sha256=/')
Always verify the signature using the raw request body. If you parse JSON first, the signature check can fail.