FeedIndex

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 timestamp field in the body and discarding payloads older than a few minutes.

Headers

HeaderDescription
X-FeedIndex-SignatureHMAC-SHA256 hex digest of the request body
X-FeedIndex-EventThe 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 timestamp field in the JSON body can be used to reject replayed requests (e.g., discard payloads older than 5 minutes)

On this page