Overview
Securing your webhook endpoints is critical to ensure that webhook requests are coming from Gu1 and not from malicious actors. This guide covers how to verify webhook signatures, implement security best practices, and avoid common security mistakes.Signature Verification
Gu1 signs all webhook requests with an HMAC SHA-256 signature using your webhook secret. The signature is sent in theX-Webhook-Signature header, allowing you to verify that the request is authentic.
How Signature Verification Works
- Gu1 generates a signature: When sending a webhook, Gu1 creates an HMAC SHA-256 hash of the raw request body using your webhook secret
- Signature is sent in header: The signature is included in the
X-Webhook-Signatureheader - Your server recalculates: Your endpoint recalculates the signature using the same secret and raw body
- Compare signatures: If the signatures match, the webhook is authentic
Signature Verification Examples
Node.js (Express)
Node.js
Critical: You must verify the signature using the raw request body before itβs parsed as JSON. If you verify against the parsed JSON body (e.g.,
JSON.stringify(req.body)), the signature will not match because JSON formatting may differ.Python (Flask)
Python
Go (Gin)
Go
Raw Body vs Parsed JSON
A common mistake is to verify the signature using the parsed JSON object instead of the raw request body. This will always fail because JSON formatting can differ.What Gu1 signs (and what it does not)
Gu1 computesHMAC-SHA256(secret, raw_request_body) and sends the hex digest in X-Webhook-Signature.
Use a timing-safe comparison when checking the signature (for example
crypto.timingSafeEqual in Node.js). See the security best practices section below.Webhook history in the dashboard
The Webhook Monitor shows the payload for debugging and support. That view is not the exact byte string that was signed at delivery time. Pretty-printing, copying from the UI, or runningJSON.stringify() on a parsed object can produce a different string and make a correct delivery look invalid.
To debug a failed delivery, compare the X-Webhook-Signature header your endpoint received with an HMAC computed over the raw body of that same HTTP request. Do not re-verify from the dashboard JSON alone.
Intermittent signature failures
If verification works for some events but returns401 Invalid signature for others with the same webhook secret and endpoint, the usual causes are:
- Parsed JSON re-stringified β
JSON.stringify(req.body)afterexpress.json()(or equivalent) does not reliably reproduce Gu1βs body bytes. Different payloads (key order, nested shape, number formatting) can make this fail only sometimes. - Middleware that mutates the body β deduplicating arrays, stripping
nullfields, sorting keys, or normalizing strings before verification changes the signed input. - Wrong secret β secret regenerated in the dashboard while an old value remains in your environment.
- Missing signature header β if the webhook has no secret configured, Gu1 may omit
X-Webhook-Signature; treating a missing header as an invalid signature is expected.
Idempotency Patterns
Webhooks may be delivered more than once due to network issues, timeouts, or retries. Implement idempotency to ensure you process each webhook only once.Database-Based Idempotency
Store processed webhook IDs in your database:Node.js
Cache-Based Idempotency
For high-volume webhooks, use a cache like Redis:Node.js with Redis
Python with Redis
Security Best Practices
1. Always Verify Signatures
1. Always Verify Signatures
Never skip signature verification in production environments. This is your primary defense against fake webhooks.
2. Use HTTPS Only
2. Use HTTPS Only
Configure your webhook endpoints to use HTTPS only. Reject HTTP requests:
3. Validate Event Types
3. Validate Event Types
Only process event types youβre expecting:
4. Implement Rate Limiting
4. Implement Rate Limiting
Protect your endpoint from abuse with rate limiting:
5. Store Webhook Secrets Securely
5. Store Webhook Secrets Securely
Never hardcode webhook secrets. Use environment variables or secret management:For production, use a secret manager:
- AWS Secrets Manager
- HashiCorp Vault
- Azure Key Vault
- Google Secret Manager
6. Validate Payload Structure
6. Validate Payload Structure
Validate the webhook payload structure before processing:
7. Use Timing-Safe Comparisons
7. Use Timing-Safe Comparisons
When comparing signatures, use timing-safe comparison functions to prevent timing attacks:
8. Implement Webhook Logs
8. Implement Webhook Logs
Log all webhook attempts for auditing and debugging:
9. Return 200 Quickly
9. Return 200 Quickly
Respond with 200 status code quickly to prevent retries. Process heavy work asynchronously:
10. Implement Retry Logic
10. Implement Retry Logic
If webhook processing fails, store it for retry:
Common Security Mistakes to Avoid
1. Skipping Signature Verification
2. Verifying Parsed JSON Instead of Raw Body
3. Using HTTP Instead of HTTPS
4. Hardcoding Secrets
5. Not Implementing Idempotency
6. Exposing Errors to Clients
7. Not Validating Event Types
8. Using Weak Secrets
Testing Webhook Security
Test Invalid Signatures
Test Replay Attacks
Send the same webhook twice and verify idempotency:Monitoring and Alerting
Set up monitoring for webhook security:Next Steps
Webhook Configuration
Learn how to configure webhooks
Entity Events
Handle entity lifecycle events
KYC Events
Process KYC verification events
Rule Events
Respond to compliance rules