Link copied.
DigitalWerks Insights

Webhook Signature Validation: Prove an Event Came From the Right System

Webhook signatures help verify that an event came from the expected sender, but reliable integrations also need raw-body validation, replay protection, schema checks, and downstream reconciliation.
Editorial verification gate with a signed webhook payload, key card, and rejected delivery
DigitalWerks field note

A webhook endpoint is an internet-facing doorway. If it accepts any request that looks like JSON, an attacker or a misconfigured system can make your application process data it did not actually receive from the intended provider.

Signature validation adds a specific check before business logic runs: can the receiver prove that this exact request was created with the shared secret held by the sender? That check is useful, but it is only one part of a reliable webhook workflow. You still need replay protection, event validation, safe logging, and reconciliation after the request is accepted.

What a webhook signature proves

Most signed webhooks use a message authentication code, commonly HMAC. The sender combines a shared secret with the exact request body and a hash algorithm such as SHA-256. It sends the resulting signature in a header. The receiver calculates the signature again with its copy of the secret and compares the two values.

A matching signature gives the receiver evidence that:

  • The request body was created with the expected secret.
  • The body was not changed between signing and verification.
  • The request likely came through the configured sender path.

It does not prove that the event is new, that the event type is allowed, that the referenced record exists, or that the downstream update succeeded. Those are separate controls.

For example, GitHub documents HMAC-SHA256 validation through the X-Hub-Signature-256 header. Its guidance also recommends a constant-time comparison and warns that the original payload must be used. HMAC itself is described in RFC 2104.

Verify the raw body before parsing JSON

The most common implementation mistake is verifying a reconstructed object instead of the bytes that were signed. JSON can represent the same data in different ways. Whitespace, key order, escaping, line endings, and character encoding can change the body even when the parsed object looks equivalent.

The safe request path is:

  1. Read the request body once as raw bytes or as the exact text provided by the framework.
  2. Read the provider’s signature header without normalizing it into a different format.
  3. Calculate the expected HMAC from the raw body and the server-side secret.
  4. Compare the expected and received signatures with a constant-time comparison.
  5. Only after verification succeeds, parse the body and apply business rules.

Framework middleware can interfere with this sequence. A JSON parser, request sanitizer, proxy, or body decompression layer may alter what your handler sees. If a provider’s test signature fails even though the secret is correct, capture the exact bytes at the application boundary and compare them with the provider’s delivery record. Do not solve the problem by weakening verification.

Keep the verification boundary small

Signature verification should happen at the edge of the endpoint, before database writes, CRM calls, email triggers, or queue publication. A useful handler separates four stages:

  1. Transport checks: confirm HTTPS, expected method, content type, size limits, and required headers.
  2. Authenticity checks: select the correct secret, calculate the HMAC, and compare it safely.
  3. Event checks: validate the event identifier, type, schema version, timestamp if provided, and required fields.
  4. Business processing: record the event, update systems, and reconcile the result.

This separation makes failures easier to diagnose. A missing signature is different from a bad signature. A valid signature with an unsupported event type is different again. Each outcome should have its own status, metric, and operational response.

Use the provider’s delivery ID for replay protection

A valid signature does not make a request unique. An attacker who captures a valid request could send it again, and a provider may legitimately retry a delivery after a timeout. If the handler creates a CRM record or sends a message every time it sees a valid request, a repeated delivery can create duplicate work.

When the provider supplies a delivery ID, store it before business processing and enforce uniqueness at the database level. GitHub, for example, documents X-GitHub-Delivery as a globally unique identifier for an event. Other providers use names such as event ID, delivery ID, or request ID.

A practical event record can include:

  • Provider name and webhook configuration ID.
  • Delivery ID and event type.
  • Signature verification result.
  • Received timestamp and provider timestamp, if available.
  • Schema validation result.
  • Processing status, attempt count, and downstream references.
  • A redacted payload hash or encrypted payload reference, subject to retention rules.

On a duplicate delivery, return the provider’s expected success response only when the original event is already known to have been processed or safely queued. If the first attempt is still in progress, use a clear in-progress state rather than starting a second business operation.

Do not use signatures as the only authorization rule

A signature answers “was this body signed with the configured secret?” It does not answer “should this application act on this event?” Add an allowlist for event types, validate the account or tenant identifier, and confirm that the referenced object belongs to the expected environment.

This matters when one provider account serves multiple websites, business units, or environments. A valid event from a test account should not update production records simply because the secret was copied into the production configuration.

Also keep secrets separate by environment and endpoint where possible. Store them in a secrets manager or protected server configuration, rotate them through an intentional rollout, and never place them in source control or ordinary logs.

Return responses that support reliable delivery

Webhook senders usually need a quick response. A receiver that performs a long CRM update or report refresh before responding is more likely to time out and trigger a retry. A better pattern is to verify and validate the request, record or enqueue the event, return the appropriate success response, and process the durable work asynchronously.

That pattern only works when the queue or event record is trustworthy. Test what happens when the database write succeeds but the queue publish fails, when the worker crashes after the CRM update, and when a retry arrives while the first attempt is still being processed. Your earlier work on idempotency, rejected-record handling, and reconciliation still applies after signature validation.

Test the full boundary, not just the hash

A unit test for the HMAC function is necessary but insufficient. Build a test matrix that includes:

  • The provider’s published sample secret, payload, and expected signature.
  • A changed body with the original signature.
  • A changed signature with the original body.
  • A missing, malformed, truncated, or wrong-algorithm header.
  • Unicode content and escaped characters.
  • Extra whitespace, different line endings, and middleware-parsed bodies.
  • A valid signature for an unsupported event type.
  • A valid duplicate delivery ID.
  • A valid event that fails downstream validation or processing.
  • Secret rotation during the overlap window.

For each case, verify the HTTP response, durable event status, log fields, alert behavior, and downstream side effects. The most important assertion is not only that an invalid request is rejected. It is that no CRM update, email, donation record, or analytics event occurs before authenticity and schema checks pass.

Where DigitalWerks can help

Webhook security is part of the larger data path. The endpoint, queue, database, CRM, analytics layer, and reporting workflow all need compatible identifiers, clear ownership, and observable failure states.

DigitalWerks can review a webhook workflow from request capture through downstream reconciliation, including signature handling, secret rotation, replay protection, privacy-aware logging, queue behavior, and validation of the final record. The goal is not just to reject suspicious requests. It is to make every accepted event explainable and recoverable.

Final checklist

  • Use the exact raw request body for signature calculation.
  • Verify the signature before parsing or processing the event.
  • Use HMAC-SHA256 or the provider’s documented stronger method.
  • Compare signatures with a constant-time function.
  • Keep secrets out of source control and logs.
  • Validate event type, tenant, environment, schema, and required fields.
  • Deduplicate using the provider’s delivery or event ID.
  • Record enough redacted evidence to investigate failures.
  • Return quickly after durable acceptance and process slow work safely.
  • Test invalid signatures, retries, duplicates, rotation, and downstream failures.

A signature is a gate, not a complete integration strategy. Once the receiver treats authenticity, uniqueness, schema, processing, and reconciliation as separate checkpoints, webhook-driven workflows become easier to secure, test, and operate.

Useful? Pass it on.Share this field note with someone who can use it.
From insight to implementation

Make the rest of your digital system work this clearly.

DigitalWerks connects strategy, websites, software, analytics, integrations, and AI-ready operations into one dependable system.

Start a conversation