Verify Webhook Signatures
Signature header
Brale signs webhook deliveries with HMAC-SHA256. Each request includes:- The header value is the lowercase hex-encoded HMAC-SHA256 digest (no prefix like
v1=, no version, no timestamp). - The HMAC is computed over the exact raw request body bytes (no canonicalization).
- The HMAC key is the Base64URL-decoded
sharedSecretvalue returned when creating the subscription.
Shared secret
When you create a webhook subscription, Brale returns asharedSecret.
Node.js / TypeScript example
Express example
Mount the webhook route withexpress.raw() before express.json().
Python example
Common signature verification failures
| Symptom | Likely cause | Fix |
|---|---|---|
401 invalid_signature | Using the wrong secret | Confirm you copied the sharedSecret from the same subscription receiving the event |
401 invalid_signature after updating .env | Server still running with old env | Restart your server |
401 invalid_signature in Express | You verified after JSON parsing | Capture raw body with express.raw() before express.json() |
401 invalid_signature in tests | Signed one serialized body but sent another | Sign the exact bytes you send |
| Signature length mismatch | Header is missing or malformed | Validate header exists before comparing |
| Works locally but not in production | Different env var or subscription secret | Confirm production env uses the correct sharedSecret |