Every webhook delivery from InfraAudit includes an X-InfraAudit-Signature header. Verifying this header before processing the payload confirms the request came from InfraAudit and was not tampered with in transit.
X-InfraAudit-Signature: sha256=<hex-encoded-hmac>
The signature is an HMAC-SHA256 of the raw request body, computed with the webhook’s secret key. The secret is shown once when you create the webhook — store it securely.
Verification examples
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"net/http"
)
func verifySignature(r *http.Request, body []byte, secret string) bool {
signature := r.Header.Get("X-InfraAudit-Signature")
if signature == "" {
return false
}
mac := hmac.New(sha256.New, []byte(secret))
mac.Write(body)
expected := "sha256=" + hex.EncodeToString(mac.Sum(nil))
return hmac.Equal([]byte(signature), []byte(expected))
}
Important: use the raw request body
The signature is computed against the raw request body bytes, before JSON parsing. Read the raw bytes before your framework parses the body:
- Express: use
express.raw({ type: 'application/json' }) on the route
- Flask: use
request.get_data() before request.get_json()
Using a parsed/re-serialized body for verification will fail — whitespace changes and key ordering differences will produce a different HMAC.
Use timing-safe comparison
Always use a timing-safe comparison function to prevent timing attacks:
- Go:
hmac.Equal
- Node.js:
crypto.timingSafeEqual
- Python:
hmac.compare_digest
Standard string equality (==) is not safe for this purpose.
Rotating the webhook secret
To rotate a webhook secret:
- Delete the existing webhook.
- Create a new webhook with the same URL and event subscriptions. A new secret is generated.
- Update your receiver with the new secret.
For SaaS Enterprise customers, contact support to rotate the secret in place without recreating the webhook.