A webhook signature is a cryptographic value attached to an HTTP webhook request that lets the receiving system verify who sent the event and that the payload was not modified in transit. In automation security, it is the standard control that turns an open callback endpoint into one that accepts only genuine events from a trusted sender.
Webhooks drive many automated workflows: a payment provider reports a settled charge, a code repository announces a push, or a form service delivers a submission. Because the receiving endpoint is usually reachable from the public internet, anyone who discovers its address can post fake events to it. The signature closes that gap without requiring the sender to hold an account or session on the receiving side.
How a webhook signature is computed and verified
A webhook signature is produced by applying a keyed cryptographic function to the exact bytes of the request body, usually combined with a timestamp and sometimes an event identifier. The most common construction is HMAC with SHA-256, where sender and receiver share a secret key that never travels with the request.
- The sender serializes the event into a body, typically JSON, and records the current time.
- It builds a signed string, for example the timestamp, a separator and the raw body.
- It computes HMAC-SHA256 over the signed string with the shared secret and encodes the result in hex or Base64.
- It sends the signature and timestamp in HTTP headers alongside the body.
- The receiver repeats the computation on the raw received bytes with its copy of the secret and compares the two values in constant time.
If the values match, the receiver knows the message came from a holder of the secret and that not a single byte changed. If they differ, the request is rejected, usually with an HTTP 401 or 400 status, and the event is not processed.
Signature schemes and their parameters
Webhook providers differ in algorithm, key model and header layout, and the receiver must follow the sender’s scheme exactly. The table below summarizes the main approaches seen in practice.
| Scheme | Key model | Typical output | Main trade-off |
|---|---|---|---|
| HMAC-SHA256 | Shared symmetric secret | 64 hex characters | Fast and simple, but both sides hold the same key |
| HMAC-SHA1 | Shared symmetric secret | 40 hex characters | Legacy; acceptable within HMAC but best phased out |
| Ed25519 signature | Sender private key, public verification key | 64-byte signature | Receiver cannot forge events; key distribution is easier |
| RSA or ECDSA signature | Asymmetric key pair, often with certificates | 256 to 512 bytes | Strong non-repudiation, heavier computation |
| HTTP Message Signatures | Symmetric or asymmetric, standardized fields | Signature and Signature-Input headers | Interoperable, but more complex to implement |
Key length matters as much as the algorithm. For HMAC, a secret of at least 32 random bytes matches the strength of SHA-256. The Standard Webhooks specification and RFC 9421 on HTTP Message Signatures both describe interoperable layouts, which reduce the risk of custom parsing errors.
Webhook signature compared with other endpoint protections
A webhook signature protects message integrity and origin, which is different from controlling who may reach the endpoint or encrypting the channel. Mature integrations layer several controls, because each one blocks a different attack.
| Control | Proves sender identity | Detects tampering | Main limitation |
|---|---|---|---|
| Webhook signature | Yes, by key possession | Yes | Depends on secret hygiene on both sides |
| TLS (HTTPS) | Server only, unless mutual TLS | In transit only | Does not authenticate the sender of an event |
| IP allowlisting | Weakly, by network origin | No | Breaks when provider ranges change |
| Static token in URL or header | Yes, if the token stays secret | No | Token leaks through logs and proxies |
| Mutual TLS | Yes, by client certificate | In transit only | Certificate management overhead |
The secret behind the signature belongs in a credential vault, not in source code or workflow definitions, and the verifying process should run under a dedicated service account with minimal rights. Each accepted and rejected event should land in the audit trail, so investigators can reconstruct what triggered an automation.
Replay protection and secret rotation
A valid signature does not stop an attacker from resending a captured request, because the replayed copy still verifies. Replay protection therefore relies on the signed timestamp and on idempotent processing.
- Tolerance window: reject requests whose timestamp differs from the receiver clock by more than about five minutes; many providers recommend values between 3 and 10 minutes.
- Event identifier cache: store processed event IDs for at least the tolerance window and ignore duplicates.
- Idempotent handlers: design actions so that processing the same event twice yields the same result.
- Clock synchronization: keep receiver clocks on NTP, because drift causes false rejections.
Secret rotation limits the damage of a leaked key. A safe rotation runs in overlapping phases, during which the sender may sign with both secrets and the receiver accepts either one, so that no events are lost during the switch.
| Phase | Sender behavior | Receiver behavior |
|---|---|---|
| Preparation | Generates a new secret | Stores the new secret next to the old one |
| Overlap | Signs with the new secret or both | Accepts a match against either secret |
| Cutover | Signs only with the new secret | Still accepts both briefly |
| Retirement | Destroys the old secret | Removes the old secret and logs the change |
Implementation mistakes that break verification
Most webhook signature failures come from how the receiver handles bytes and comparisons, not from weak cryptography. The following problems recur across frameworks and automation platforms.
| Mistake | Consequence | Fix |
|---|---|---|
| Verifying parsed JSON instead of raw body | Valid events fail after re-serialization | Capture the raw request bytes before parsing |
| Plain string comparison | Timing side channel can leak the signature | Use a constant-time comparison function |
| Ignoring the timestamp | Captured requests can be replayed | Enforce a tolerance window and dedupe IDs |
| Secret stored in workflow code | Leak through repositories or exports | Load the secret from a vault at runtime |
| Processing before verifying | Forged events trigger actions | Verify first, then enqueue the event |
A further pitfall is logging full requests with headers, which can expose signatures and payload data. Log the event ID, the verification result and the timestamp instead, and treat a sudden rise in rejected signatures as a possible attack or misconfigured rotation.
A plain-language summary
Think of a webhook as a letter that one computer system mails to another to say that something just happened. Anyone can drop a letter into a mailbox, so the receiver needs a way to tell real letters from fakes.
A webhook signature works like a wax seal made with a private stamp. Only the sender and the receiver know the stamp. The receiver checks the seal on every letter, and if the seal is wrong or the letter was opened and changed, it throws the letter away. The key point is that only signed, unchanged messages may start an automated action.
An example from practice
An online store runs an automation that marks orders as paid and releases them to the warehouse whenever its payment provider sends a payment-succeeded webhook. Before signatures were checked, a tester showed that a simple scripted POST request to the public endpoint could mark an unpaid order as paid.
The integration team changed the handler to read the raw request body, compute HMAC-SHA256 with a 32-byte secret loaded from the company vault, compare it in constant time and reject timestamps older than 300 seconds. Processed event IDs are kept for 24 hours to drop duplicates.
After the change, forged requests receive a 401 response and appear in the audit trail with their source address. Fulfillment now starts only for events that the payment provider genuinely signed, and a later secret rotation ran with a two-day overlap without losing a single order.