Webhooks Authentication

Duda can sign requests using the HMAC-SHA256 algorithm to allow your app to verify the authenticity of the sender (Duda) and of the payload.

📘

This feature is available only for managed accounts

To get access to this feature, please contact your account manager or Duda support.

Signature generation and decoding

The signature value is calculated as follows:

  1. Signature = base64(hmac-sha256(secret-key, timestamp + "." + message))

  2. Where timestamp is the value of the x-duda-signature-timestamp request header.

  3. message is the actual request body.

  4. "." is a string separating the 2 values.

  5. secret-key your unique key you received from Duda, decoded using base64 and UTF-8.

This calculation is done by Duda and the value is added to the webhook in the x-duda-signature request header.

The same calculation should be made by the application and compared against the header to assert the message was signed by us using your secret key.

An example with data

The request body is {'key1':'world','key2':'world'} the timestamp (x-duda-signature-timestamp header) is 1570350275357 and our secret key is mysecretsecret.

Calculating base64(hmac-sha256(secret-key, timestamp + "." + message)) results in +DCfT1wIMUiaZnlZB4u59/d5wkXKA89lv67Ov66vnyc= which is the value we will find in x-duda-signature header of the signed request.

Code examples

String getHMAC(String timestamp,String message) {
        String secretKey = ...;
        SecretKeySpec signingKey = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), "HmacSHA256");

        String input = timestamp + "." + message;
        Mac mac = Mac.getInstance("HmacSHA256");
        mac.init(signingKey);
        byte[] rawHmac = mac.doFinal(input.getBytes(StandardCharsets.UTF_8));
        return new String(Base64.getEncoder().encode((rawHmac)));
}


String body = request.getBody();
String timestamp = request.getHeader("x-duda-signature-timestamp");

String hmac = getHMAC(timestamp, body);
String signautreHeader = request.getHeader("x-duda-signature");

assert hmac.equals(signautreHeader);
const crypto = require('crypto');

const sig = req.headers["x-duda-signature"];
const time = req.headers["x-duda-signature-timestamp"];
const body = JSON.stringify(req.body);

const decoded = Buffer.from(<secret-key>, "base64").toString("utf8");
const check = crypto.createHmac("sha256", decoded)
    .update(`${time}.${body}`)
    .digest("base64");

assert(sig === check);

Did this page help you?