Signature Verification
Verify webhook signatures to ensure payloads are authentic.
Every webhook request includes an HMAC-SHA256 signature so you can verify it came from FeedIndex.
Why this works
The signature is an HMAC — a keyed hash. Anyone can hash a payload, but only someone who knows your signing secret can produce a signature that matches when you recompute it on your end. The secret is shared only between FeedIndex and your server; nobody else ever sees it.
That's what makes verification safe:
- Forged requests fail. If an attacker POSTs their own payload to your webhook URL, they can't compute the right signature without the secret, so your comparison rejects it.
- Tampered requests fail. Changing even one byte of the body invalidates the signature, so a real request can't be modified in transit.
- Replayed requests can be rejected by checking the
timestampfield in the body and discarding payloads older than a few minutes.
Headers
| Header | Description |
|---|---|
X-FeedIndex-Signature | HMAC-SHA256 hex digest of the request body |
X-FeedIndex-Event | The event type (e.g., post.created) |
Verification
Compute the HMAC-SHA256 of the raw request body using your webhook signing secret, then compare it to the X-FeedIndex-Signature header.
Node.js example
import crypto from "crypto";
function verifyWebhook(body, signature, secret) {
const expected = crypto
.createHmac("sha256", secret)
.update(body)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}Python example
import hmac
import hashlib
def verify_webhook(body: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(
secret.encode(), body, hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, expected)Security tips
- Always use a timing-safe comparison to prevent timing attacks
- Store your signing secret securely (environment variable, not source code)
- The
timestampfield in the JSON body can be used to reject replayed requests (e.g., discard payloads older than 5 minutes)