Safeguard
Developer Tools•

How should an SDK help customers verify webhook signatures?

Ship a verify helper that uses HMAC over the raw body, constant time comparison and a timestamp window. See the design steps, a code sketch and test cases.

Safeguard Security Team
4 min read

An SDK should include a webhook verification helper that computes an HMAC over the raw request body, compares it to the signature header in constant time, and rejects stale timestamps. Make the safe path one function call, so customers do not write their own comparison and get it wrong.

Why the helper belongs in the SDK

If you only document the algorithm, every customer reimplements it. Common mistakes follow: parsing the JSON first and signing the re-serialised text, comparing with an ordinary equality check, ignoring replays, and logging the secret. A helper in the SDK removes those choices.

The Python standard library documentation is direct about one of them: when comparing a computed digest with an externally supplied one in a verification routine, it recommends the compare_digest function rather than the equality operator, to reduce the vulnerability to timing attacks. That function is described as designed to avoid content based short circuiting.

What the helper should do

  1. Take the raw bytes of the body exactly as received, the signature header value and the endpoint secret. Parsers and framework middleware often alter the body, so say clearly in docs that verification must happen before parsing.
  2. Compute HMAC with a strong hash over a defined string. A common design signs the timestamp and the body joined by a separator, so the timestamp is covered by the signature.
  3. Compare in constant time using the language's dedicated function.
  4. Check the timestamp against the current time with a tolerance, and reject anything outside it. This limits replay of captured requests.
  5. Return a clear failure type that does not echo the expected signature.
  6. Support more than one active secret during rotation, so customers can roll keys without dropping events.

A sketch

import hmac, hashlib, time

def verify(body: bytes, timestamp: str, signature: str, secret: bytes, tolerance=300):
    if abs(time.time() - int(timestamp)) > tolerance:
        raise ValueError("timestamp outside tolerance")
    signed = timestamp.encode() + b"." + body
    expected = hmac.new(secret, signed, hashlib.sha256).hexdigest()
    if not hmac.compare_digest(expected, signature):
        raise ValueError("signature mismatch")

This is a teaching sketch, not a drop in implementation. Add error handling for a malformed timestamp and for multiple signature values.

Design choices at a glance

ChoiceSafer default
Input to the signatureRaw body bytes plus timestamp
ComparisonConstant time function
Replay protectionTimestamp window, plus event ID tracking for strict cases
Secret handlingPer endpoint secret, never logged, rotation supported
Failure behaviorReject with a generic error and a 4xx status

Tests to ship with the helper

  • A valid signature passes.
  • A body changed by one byte fails.
  • A timestamp outside the window fails.
  • A signature in the wrong case or length fails without throwing an unexpected exception.
  • Two secrets, one old and one new, both verify during rotation.

Publish these as examples customers can copy. Also document the status code your senders expect so retries behave, as covered in safe retry rules.

Quick check

Why not compare signatures with the equality operator?

Ordinary comparison can stop at the first differing character, which can leak timing information. The Python documentation recommends compare_digest for this purpose.

Does a timestamp prevent all replays?

It limits them to the tolerance window. For stricter needs, also record event IDs you have already processed.

Safeguard's policies and gates can check that pull requests use your approved helper, and its dependency scanning shows which crypto libraries are in the tree. Try the free scan.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.