Validating Webhook Signatures
When you configure a webhook with a signing secret, OpnForm signs each webhook request with an HMAC-SHA256 signature. This allows you to verify that:- The webhook came from OpnForm (authenticity)
- The payload hasn’t been modified in transit (integrity)
Understanding the Signature
Each webhook request includes anX-Webhook-Signature header with the format:
webhook_secretis the secret you provided when creating the webhookrequest_bodyis the raw JSON payload
Validation Steps
- Extract the signature from the
X-Webhook-Signatureheader - Remove the
sha256=prefix - Calculate the expected signature using your webhook secret and the raw request body
- Compare the received signature with the calculated signature
- Reject the webhook if signatures don’t match
Always use the raw request body (as bytes/string before parsing) when calculating the signature. Parsing JSON and re-serializing can produce different output and cause signature mismatches.
Implementation Examples
Custom Headers
In addition to the signature header, OpnForm will send any custom headers you configured when creating the webhook. These can include authentication tokens, API keys, or other identifiers. Example webhook request with custom headers:Security Best Practices
- Use HTTPS only: Always use HTTPS endpoints for webhooks to prevent man-in-the-middle attacks
- Strong secrets: Use cryptographically random secrets at least 12 characters long
- Constant-time comparison: Use timing-safe comparison functions to prevent timing attacks
- Validate signatures first: Verify the signature before parsing or processing the webhook data
- Store secrets securely: Never commit secrets to version control; use environment variables or secret managers
- Rotate regularly: Consider rotating your webhook secret periodically
- Log verification failures: Track failed signature validations to detect potential attacks
Troubleshooting
Signature Mismatch
If you’re consistently getting signature mismatches:- Verify the raw body: Ensure you’re using the raw request body (before JSON parsing) to calculate the signature
- Check the secret: Confirm you’re using the exact secret from the webhook configuration
- Character encoding: Ensure both the secret and body are handled with correct UTF-8 encoding
- Middleware order: If using middleware, ensure raw body capture happens before JSON parsing
- Test with cURL: Use the cURL example above to manually test signature generation
Missing Signature Header
If theX-Webhook-Signature header is missing:
- Verify you provided a
webhook_secretwhen creating the webhook - Check your webhook status is
active - Review the integration event logs for any errors during webhook delivery