Verifying Webhook Signatures
Every webhook delivery from WhoComply is signed with your endpoint's signing secret. Always verify the signature before processing the payload.
Signature Format
Each request includes an X-Whocomply-Signature header:
X-Whocomply-Signature: t=1713369600,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8f9
The header contains two values separated by a comma:
t— Unix timestamp (seconds) when the signature was generatedv1— HMAC-SHA256 hex digest
Verification Steps
- Extract the
tandv1values from the header - Build the signed payload:
{t}.{raw_request_body} - Compute HMAC-SHA256 of that payload using your signing secret
- Compare your computed signature with
v1(constant-time comparison) - Check that
tis within 5 minutes of your server's current time (replay protection)
Code Examples
# Extract values
HEADER="t=1713369600,v1=5257a869..."
TIMESTAMP=$(echo "$HEADER" | grep -o 't=[0-9]*' | cut -d= -f2)
SIGNATURE=$(echo "$HEADER" | grep -o 'v1=[a-f0-9]*' | cut -d= -f2)
# Compute expected signature
EXPECTED=$(echo -n "${TIMESTAMP}.${BODY}" | \
openssl dgst -sha256 -hmac "$SIGNING_SECRET" | awk '{print $2}')
# Compare
if [ "$EXPECTED" = "$SIGNATURE" ]; then
echo "Valid"
fi
Replay Protection
The timestamp t prevents replay attacks. Reject any webhook where the timestamp is more than 5 minutes from your server's clock. This ensures an attacker cannot re-send an intercepted webhook payload later.
If your server's clock is significantly out of sync, you may need to increase the tolerance window. However, keep it as small as practical.