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:

  1. Signature generation: Yuno creates an HMAC signature by hashing the webhook payload with your client secret key using the SHA-256 algorithm
  2. Header inclusion: The signature is included in the x-hmac-signature HTTP header
  3. Verification: Your server extracts the signature from the header, recreates it using the same payload and secret key, then compares
  4. 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"
    }
  }
}

Related documentation