Pracandy
← Newsroom

Features

Verifying a Webhook Properly

Signatures, raw bodies, idempotency and replay. The mistakes that grant access for free.

1 October 2026

Developer typing on a laptop in front of monitors
Photo: Christina Morillo, via Pexels

The Signature Check

To verify a webhook signature, you must compare a cryptographic hash of the raw request body against a header value provided by the sender. This process confirms that the payload has not been altered in transit and originates from the expected source.

Many developers make the critical error of parsing the JSON body before computing the hash. Webhook providers sign the exact bytes sent over the wire. If you parse the JSON into an object and then re-serialize it, the byte order, whitespace, or encoding may change. A single altered byte breaks the hash match. The signature verification must happen on the raw buffer, before any parsing occurs. If the computed hash does not match the provided signature, reject the request immediately. Do not log the payload or attempt to process it. This is the primary gatekeeper for your endpoint.

Handling Raw Bodies in Node

When building services like Instalaz, which runs as a separate Node process, you must configure your framework to retain the raw body. Most HTTP libraries in Node.js expose a raw body property, but this is often disabled by default to save memory. You must explicitly enable it. The memory cost is negligible for typical webhook payloads. If you use a framework that does not expose the raw buffer, you are forced to buffer the stream manually. Failing to do so means you only have the parsed object, making proper verification impossible. The signature is a promise about the exact bytes received. If your code cannot see those bytes, you cannot verify the promise.

Idempotency and Replay Protection

Networks are unreliable. Senders often retry requests if they do not receive a timely 200 OK response. This means your endpoint may receive the same event multiple times. Without idempotency, a single successful payment or scheduled post could be processed twice. You must store a unique ID for each event. Before processing, check if this ID has already been handled. If it has, return a 200 OK immediately without re-executing the logic. This prevents double-charging or duplicate actions. The check must be atomic. Two concurrent requests with the same ID should not both pass the check. Use a database unique constraint or a distributed lock to ensure that only one instance of a given event ID is processed. This is not optional. It is the only way to maintain data integrity in the face of network retries.

Replay Attacks and Timestamps

A valid signature does not guarantee the request is current. An attacker who captures a valid request can replay it later. To prevent this, check the timestamp included in the webhook header. Reject any request that is older than a reasonable window, such as five minutes. This limits the window of opportunity for replay attacks. Combine this with a nonce or event ID to ensure that even if the timestamp is valid, the specific event has not already been processed. The timestamp check is a coarse filter. The idempotency check is the fine filter. Both are necessary. Without the timestamp check, an attacker can replay a valid request indefinitely. Without the idempotency check, a legitimate retry can corrupt your data. The combination of signature verification, raw body handling, timestamp validation, and idempotency forms a complete defense. Each layer addresses a specific failure mode. Omitting any one of them leaves a gap. The goal is not to be perfect, but to be resilient. Design your system to assume that every request is an attack until proven otherwise. This mindset leads to safer code. It also leads to fewer production issues. The work is straightforward, but it must be done correctly. There is no shortcut around the raw body check. There is no substitute for idempotency. Do the work. It is not hard. It is just necessary. For more on how we handle technical details in our products, see Instalaz.