Using a Webhook Secret
  • 26 Aug 2024
  • 2 Minutes to read
  • Dark
    Light
  • PDF

Using a Webhook Secret

  • Dark
    Light
  • PDF

Article summary

A major part of securing Webhooks involves the verification of the payload received

When your Webhook subscription was setup you received a unique "secret" for that particular subscription.

NOTE: There can be an exception to this if the Webhook Publisher you subscribe to has disabled signature security.

Our Webhooks include the ability to use this received “secret” to validate that the published message was really sent from our Webhook Dispatcher. We add a header called “X-VWD-Signature-V1” along with each of our published Webhook requests.

How signature verification works

Signature verification makes use of the Hash-based Message Authentication Code (HMAC) for authenticating and validating webhooks.

An HMAC is calculated using the “secret” and the cryptographic hash function SHA-256. The resulting HMAC, which becomes the signature of the webhook, is then used to authenticate the webhook and validate its payload.

The “secret” is known by both the webhook producer and consumer. This secret is often referred to as the webhook signing key.

  1. When sending a webhook, the Webhook Dispatcher uses this secret and an HMAC hashing algorithm (SHA-256) to create a cryptographic hash of the webhook payload. This cryptographic hash is the webhook’s unique signature.

  2. The signature is sent in the HTTP header along with the webhook request.

  3. When the webhook arrives at the webhook URL, the receiving application takes the webhook payload and uses the secret key and the cryptographic algorithm to calculate the signature.

  4. The calculated signature is then compared with the one sent in the custom header. If there is a match then the request is valid, and if not the webhook MUST BE rejected.

Code your own verification logic

You’ll need to code up the logic in your own Webhook receiver that by using your unique secret checks the payload of the Webhook event whenever it is received by implementing SHA256 Webhook Signature Verification. The following code shows how to use the raw JSON payload to compute your own signature. You then must verify it matches the signature from the “X-VWD-Signature-V1” header.

public static string ComputeHash(string secret, string payload)
{
    byte[] bytes = Encoding.UTF8.GetBytes(secret);
    var hmac = new HMACSHA256(bytes);
    bytes = Encoding.UTF8.GetBytes(payload);

    return Convert.ToBase64String(hmac.ComputeHash(bytes));
}

public static bool HashIsValid(string secret, string payload, string verify)
{
    ReadOnlySpan<byte> hashBytes = Convert.FromBase64String(ComputeHash(secret, payload));
    ReadOnlySpan<byte> verifyBytes = Convert.FromBase64String(verify);

    return CryptographicOperations.FixedTimeEquals(hashBytes, verifyBytes);
}

private static String ComputeHash(String secret, byte[] payload)
        throws InvalidKeyException, NoSuchAlgorithmException {
    String digest = "HmacSHA256";
    Mac mac = Mac.getInstance(digest);
    mac.init(new SecretKeySpec(secret.getBytes(), digest));
    String base64Hash = new String(Base64.getEncoder().encode(mac.doFinal(payload)));
    return base64Hash;
}

public static boolean HashIsValid(String secret, byte[] payload, String verify)
        throws InvalidKeyException, NoSuchAlgorithmException, UnsupportedEncodingException {
    String computedHash = ComputeHash(secret, payload);
    boolean isEqual = MessageDigest.isEqual(computedHash.getBytes(StandardCharsets.UTF_8),
            verify.getBytes(StandardCharsets.UTF_8));
    return isEqual;
}

key = bytes(args['secret'], 'utf-8')
payload = bytes(args['payload'], 'utf-8')

hmac_hash = hmac.new(key, payload, hashlib.sha256)
result = base64.b64encode(hmac_hash.digest()).decode('utf-8')

private static function computeHash($secret, $payload)
{
    $hexHash = hash_hmac('sha256', $payload, utf8_encode($secret));
    $base64Hash = base64_encode(hex2bin($hexHash));
    return $base64Hash;
}
public static function hashIsValid($secret, $payload, $verify)
{
    return hash_equals($verify, self::computeHash($secret, $payload));
}


Was this article helpful?

What's Next
Changing your password will log you out immediately. Use the new password to log back in.
First name must have atleast 2 characters. Numbers and special characters are not allowed.
Last name must have atleast 1 characters. Numbers and special characters are not allowed.
Enter a valid email
Enter a valid password
Your profile has been successfully updated.