Webhook signing
Webhook deliveries are signed so you can authenticate that Rook sent the payload and that it was not modified in transit.
Each endpoint has a secret that starts with whsec_. Use the entire secret
string, including the prefix, as the HMAC key.
Headers
| Header | Value |
|---|---|
Rook-Timestamp | Unix time in seconds when the signature was computed. |
Rook-Signature | v1= of the HMAC-SHA256 digest. Multiple v1= values may be comma-separated during secret rotation. |
Signed payload
The signed material is the timestamp, a literal ASCII dot, then the raw request body bytes (no re-encoding):
{timestamp}.{body}
Verify a delivery
1. Read Rook-Timestamp and Rook-Signature. Reject the request if either is
missing.
2. Reject the delivery if the timestamp is more than 300 seconds from the
current time (replay window).
3. Compute HMAC-SHA256(secret, "{timestamp}.{body}") and hex-encode the
digest (lowercase).
4. Compare the digest to each v1= value in Rook-Signature using a
constant-time equality check. Succeed if any matches.
# timestamp and body from the inbound HTTP request
signed_payload="${timestamp}.${body}"
expected=$(printf '%s' "$signed_payload" | openssl dgst -sha256 -hmac "$webhook_secret" | awk '{print $2}')
Respond with 2xx only after the signature verifies. If verification fails,
respond with 401 and do not act on the event.
Secret rotation
When you roll a secret, deliveries may include two v1= signatures for a
short period. Accept the request if either digest matches.