Verify Webhook Signatures (HMAC)
Learn how to verify webhook signatures using HMAC to ensure webhooks from Yuno are authentic and haven't been tampered with during transmission.
Webhook signature verification using HMAC (Hash-based Message Authentication Code) ensures that webhooks sent to your server actually originate from Yuno and haven't been intercepted or modified during transmission. This adds an extra layer of security beyond authentication methods like OAuth.
While OAuth provides authentication (verifying who is sending the request), HMAC signatures provide:
- Data integrity: Confirms the webhook payload hasn't been tampered with
- Authenticity: Verifies the webhook genuinely comes from Yuno
- Protection: Guards against man-in-the-middle attacks and replay attacks
- Compliance: Meets security requirements for handling sensitive payment data
How HMAC signatures work
When Yuno sends a webhook to your server:
- Signature generation: Yuno creates an HMAC signature by hashing the webhook payload with your client secret key using the SHA-256 algorithm
- Header inclusion: The signature is included in the
x-hmac-signatureHTTP header - Verification: Your server extracts the signature from the header, recreates it using the same payload and secret key, then compares
- Validation: If the signatures match, the webhook is authentic and unaltered
Configuration
To enable HMAC signature verification, check Use HMAC Authentication when creating or editing a webhook in the Yuno dashboard.
See Configure Webhooks for step-by-step instructions on accessing the webhook configuration panel.
What changes with HMAC
When HMAC signature verification is enabled, Yuno webhooks include an additional x-hmac-signature HTTP header. The webhook JSON payload remains unchanged.
Example webhook request with HMAC
POST /your-webhook-endpoint HTTP/1.1
Host: your-server.com
Content-Type: application/json
x-api-key: your-api-key
x-secret: your-secret
x-hmac-signature: K7gNU3sdo+OL0wNhqoVWhr3g6s1xYv72ol/pe/Unols=
{
"type": "payment",
"type_event": "payment.purchase",
"account_id": "2c05976d-1234-1234-1234-6421883de48d",
"retry": 0,
"version": 2,
"data": {
"payment": {
"id": "a546c566-1703-4fba-b334-c46e89bc97f7",
"status": "SUCCEEDED"
}
}
}Verification code example
Verify the x-hmac-signature header using the raw request body (before parsing JSON) and the same secret configured for the webhook in the Yuno dashboard.
Node.js (Express): use a body parser that keeps the raw body for the webhook route (e.g. express.raw() for that path), then:
const crypto = require('crypto');
function verifyWebhookSignature(rawBody, signatureHeader, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('base64');
return crypto.timingSafeEqual(
Buffer.from(signatureHeader, 'base64'),
Buffer.from(expected, 'base64')
);
}
// Example: const isValid = verifyWebhookSignature(req.body, req.headers['x-hmac-signature'], process.env.WEBHOOK_SECRET);Python: use the raw request body bytes and the x-hmac-signature header:
import hmac
import hashlib
import base64
def verify_webhook_signature(raw_body: bytes, signature_header: str, secret: str) -> bool:
expected = base64.b64encode(
hmac.new(secret.encode(), raw_body, hashlib.sha256).digest()
).decode()
return hmac.compare_digest(signature_header, expected)If the computed signature does not match the header, reject the webhook (e.g. return 401).
Related documentation
Updated 15 days ago