Webhook Guides

Webhook Signature Verification

Webhook signature verification proves that a request came from the expected sender and that the signed payload was not changed before processing. It should happen before routing, transformation, retry decisions, or business side effects.

The most common implementation bug is verifying a parsed JSON object instead of the exact raw request body. FastHook source authentication keeps that verification boundary at ingress and records whether accepted requests were verified.

Webhook HMAC verification over raw request body.
Most provider signatures are generated from the exact raw body. Capture and verify the raw bytes before parsing JSON or applying transformations.

How webhook signatures usually work

  1. The provider and receiver share a webhook secret or public verification key.
  2. The provider signs the raw request body, sometimes with a timestamp or message id.
  3. The provider sends the signature in a header such as Stripe-Signature or X-Hub-Signature-256.
  4. The receiver computes the expected signature over the same input.
  5. The receiver compares the signatures with a timing-safe comparison.
  6. Only verified requests move into routing and processing.

Provider signature examples

ProviderHeaderInputNotes
GitHubX-Hub-Signature-256raw bodyUses sha256= prefix.
StripeStripe-Signaturetimestamp + raw bodyUse endpoint secret and timestamp tolerance.
ShopifyX-Shopify-Hmac-Sha256raw bodyBase64 HMAC digest.
Svix / Standard Webhookswebhook-signatureid + timestamp + raw bodyUsed by several developer platforms.

Generic HMAC verification example

Verify HMAC
import crypto from "node:crypto";

function verifyWebhookHmac({ rawBody, signatureHeader, secret }) {
  const expected = crypto
    .createHmac("sha256", secret)
    .update(rawBody)
    .digest("hex");

  const received = signatureHeader.replace(/^sha256=/, "");

  return crypto.timingSafeEqual(
    Buffer.from(expected, "hex"),
    Buffer.from(received, "hex")
  );
}

FastHook source authentication

FastHook can verify provider-specific source types and generic HMAC source auth before the request is queued. Accepted requests are stored with verification evidence, while failed verification appears as a rejected source request that can be inspected without reaching downstream destinations.

Common verification failures

  • Verifying parsed JSON instead of the exact raw body.
  • Using the wrong endpoint secret for the environment.
  • Dropping the provider prefix such as sha256= at the wrong time.
  • Configuring a timestamp header for providers that do not sign timestamps.
  • Transforming the payload before provider signature verification.
  • Comparing signatures with a normal string comparison instead of timing-safe comparison.

Related guides