Skip to main content
When a webhook sink has a signing key configured, Beam signs every request with HMAC-SHA-256. Your endpoint verifies the signature to confirm the request came from Beam and was not tampered with or replayed. Signing is opt-in per webhook sink. Without a key, Beam still POSTs to your URL but adds no signature headers.

How signing works

Each request carries three headers: The signed payload is the concatenation:
Binding the nonce and timestamp into the signature means an attacker cannot replay an old request with a fresh nonce or shift the timestamp forward without invalidating the signature.

Enable signing on a sink

  1. Store your signing key as an organization secret. Pick any random high-entropy value (32+ bytes recommended).
  2. Set hash_key on the webhook sink to the secret’s name.
If you rotate the secret value, you must redeploy the pipeline for the new value to take effect. The sink will be flagged as stale until then.

Verify the signature

The verification recipe is the same in every language:
  1. Read the three headers off the incoming request.
  2. Reject if X-Webhook-Timestamp is too old (e.g. more than 5 minutes ago) — this is your replay window.
  3. Recompute sha256= + hmac_sha256(key, nonce + "." + timestamp + "." + raw_body) in hex.
  4. Compare against X-Signature-256 using a constant-time comparison.
Verify against the raw request body bytes, not a re-serialized JSON object. Any whitespace or key-order difference will change the hash and break verification.
If the sink has enable_http_encoding set, Beam signs the compressed body — the same bytes that arrive on the wire with Content-Encoding: zstd. Run signature verification on the raw request body before decompressing it; hashing the decompressed payload will not match.

Replay protection

The timestamp + nonce pair lets you reject duplicates:
  • Timestamp window — reject any request whose X-Webhook-Timestamp is more than ~5 minutes off your server clock. A short window keeps the nonce cache small.
  • Nonce cache (optional, defense-in-depth) — record each X-Webhook-Nonce you’ve accepted in a short-TTL cache (Redis, etc.) and reject repeats. Cache TTL should match your timestamp window.
For most consumers the timestamp check alone is sufficient.