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.
How webhook signatures usually work
- The provider and receiver share a webhook secret or public verification key.
- The provider signs the raw request body, sometimes with a timestamp or message id.
- The provider sends the signature in a header such as
Stripe-SignatureorX-Hub-Signature-256. - The receiver computes the expected signature over the same input.
- The receiver compares the signatures with a timing-safe comparison.
- Only verified requests move into routing and processing.
Provider signature examples
| Provider | Header | Input | Notes |
|---|---|---|---|
| GitHub | X-Hub-Signature-256 | raw body | Uses sha256= prefix. |
| Stripe | Stripe-Signature | timestamp + raw body | Use endpoint secret and timestamp tolerance. |
| Shopify | X-Shopify-Hmac-Sha256 | raw body | Base64 HMAC digest. |
| Svix / Standard Webhooks | webhook-signature | id + timestamp + raw body | Used by several developer platforms. |
Generic HMAC verification example
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.