Signature Verification#
Every webhook request from Afosto is signed using HMAC-SHA256. Verifying the signature before processing a payload ensures the request genuinely came from Afosto and that the body was not tampered with in transit.
How signing works#
- Afosto serializes the JSON payload to a UTF-8 string (HTML escaping disabled, no trailing newline)
- It computes
HMAC-SHA256(payload, endpoint_secret) - The hex-encoded digest is sent in the
X-Afosto-Hmac-Sha256request header
To verify, compute the same HMAC on your side using the raw request body (before any JSON parsing) and compare it to the header value.
⚠
Warning:Always compute the HMAC over the raw bytes of the request body. Parsing the JSON first and re-serializing it can change whitespace or key order, causing the signature to not match.
Verification examples#
Security checklist#
- Use a timing-safe comparison (
timingSafeEqual,hmac.compare_digest,hash_equals) — never a plain===string comparison. This prevents timing attacks. - Read the raw body before parsing — JSON parsers may normalize the payload, invalidating the signature.
- Store your secret securely — use an environment variable or secret manager, never hard-code it.
- Reject requests with a missing or empty signature header — treat them as untrusted.
- Use
message_idfor idempotency — a verified signature does not mean the event was not already processed.