Verify the original bytes
Webhook signatures are commonly calculated over the raw request body. If JSON middleware parses and serializes the payload first, whitespace or ordering may change and a legitimate signature will fail.
Capture the raw body before parsing and use the provider’s maintained library. Keep test and production endpoint secrets separate. During rotation, allow a short overlap in which old and new secrets can verify deliveries.
A signature can be replayed
An attacker who captures a valid payload and signature can send them again. Verify the signed timestamp and accept only a small clock tolerance. That reduces the replay window, but legitimate delivery retries still remain part of the protocol.
Make processing idempotent. Store the event id under a uniqueness constraint and let duplicates finish without repeating a charge, email, entitlement change, or irreversible transition.
- Verify signature and freshness before reading business fields.
- Return a successful response quickly and queue expensive work.
- Do not assume strict event ordering.
- Log the event id and result, not the reusable signing material.
Design for at-least-once delivery
Providers retry when your endpoint times out or returns an error. If the handler changed data but failed before responding, the next attempt must not repeat the effect.
A mature webhook flow resembles a small distributed system: authenticity, deduplication, durable queues, observability, and recovery matter more than a beautifully short controller.