Increase webhook security by validating the signature
When creating a JSON webhook turn on the option to “Add encoded signature in header” to include the webhook payload using HMAC-SHA-256 signature verification. The signature is sent in the header X-Mopinion-Signature
and is encoded using a secret token you can enter when creating the webhook.
Validating the signature in your endpoint
Extract the signature from the webhook header
Get the raw webhook payload (before parsing)
Generate a signature using your secret key
Compare the generated signature with the received signature
Code Examples
Python
import base64
import hashlib
import hmac
import json
def validate_webhook(payload: str, signature: str, secret_key: str) -> bool:
"""
Validate a webhook payload using HMAC-SHA-256.
Args:
payload (str): The raw webhook payload as a string
signature (str): The signature from the webhook header
secret_key (str): Your webhook secret key
Returns:
bool: True if the webhook is valid, False otherwise
"""
byte_key = secret_key.encode('utf-8')
byte_payload = payload.encode('utf-8')
expected_signature = base64.b64encode(
hmac.new(byte_key, byte_payload, hashlib.sha256).digest()
).decode()
return hmac.compare_digest(signature, expected_signature)
# Example usage
def webhook_handler(request):
signature = request.headers.get('X-Mopinion-Signature')
payload = request.body # Raw request body as string
secret_key = 'your_secret_key'
if validate_webhook(payload, signature, secret_key):
# Process valid webhook
data = json.loads(payload)
# ... handle the webhook data
else:
# Reject invalid webhook
raise ValueError("Invalid webhook signature")
Node.js
const crypto = require('crypto');
function validateWebhook(payload, signature, secretKey) {
const expectedSignature = crypto
.createHmac('sha256', secretKey)
.update(payload)
.digest('base64');
// Use timing-safe comparison
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}
// Example usage with Express
app.post('/webhook', (req, res) => {
const signature = req.headers['x-mopinion-signature'];
const payload = JSON.stringify(req.body);
const secretKey = 'your_secret_key';
if (validateWebhook(payload, signature, secretKey)) {
// Process valid webhook
// ... handle the webhook data
res.sendStatus(200);
} else {
res.sendStatus(401);
}
});
Important Notes
Always use timing-safe comparison methods to prevent timing attacks
Process the raw payload before parsing it as JSON
Keep your secret key secure and never expose it in client-side code
The signature is base64 encoded
The HMAC-SHA-256 algorithm is used for signature generation