Skip to main content
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.

Header format

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:
  1. Delete the existing webhook.
  2. Create a new webhook with the same URL and event subscriptions. A new secret is generated.
  3. Update your receiver with the new secret.
For SaaS Enterprise customers, contact support to rotate the secret in place without recreating the webhook.