Webhook Signature Verification

Verifying Signatures

Preczn's webhooks are sent with a signature (HMAC) that the recipient can use to verify the message originated from Preczn, and not a third party or malicious system. It is strongly recommended that webhook consumers verify these signatures before processing each message.

  

The Signing Secret

When a webhook is created, a strong unique signing secret is generated and provided for that specific webhook. This secret is used to sign all webhook requests sent by this specific webhook. The signature is then delivered along with each request in the X-Preczn-Signature header.


 

The Signature

The X-Preczn-Signature header included with each webhook event delivery contains one or more signatures. Multiple signatures may be present to allow for a zero-downtime signing secret rotation and support for different algorithms.

The current signature version is v1 and is computed as an HMAC of the webhook request body using the SHA-256 hash function. This is performed for each signing secret, and the results are concatenated using comma separation.

Example signature:
X-Preczn-Signature: v1=fd2118dc6da5fda8ae597a4ddfea31c691335b73613b15936a4ab49c632d3658

  

Verifying the Signature

Verifying the signature of a webhook request is accomplished in a few simple steps:

  1. Extract the signature(s) from the X-Preczn-Signature request header.
  2. Split the string into multiple signatures, if available, separated by the , character.
  3. Remove the version v1= prefix from the signature(s).
  4. Compute the expected signature value using the entire request body.
  5. Compare the received signature value(s) with the expected signature value.

If at least one of the received signature values matches the expected value, the request can be trusted as an authentic request from Preczn.

If none of the received signature values match the expected value, disregard and discard the request.

🔡

Character Encoding Significance

Note that Preczn utilizes UTF-8 for all string encoding, this is of great significance in the context of calculating and matching accurate HMAC signatures. When implementing X-Preczn-Signature verification, be sure to explicitly utilize UTF-8 character encoding.

Computing the Expected Signature

Computing the expected signature value is accomplished by calculating the SHA256-HMAC value for the entire request body, in hexadecimal format with all lowercase characters.

Examples:

const crypto = require('crypto');

function generateWebhookSignature(signingSecret, requestBody) {
    const hmac = crypto.createHmac('sha256', signingSecret, { encoding: "utf-8" });
    const data = hmac.update(requestBody);
    return data.digest('hex');
}
import hmac
import hashlib

def generate_webhook_signature(signing_secret, request_body):
    signing_bytes = bytearray(signing_secret.encode(encoding='UTF-8'))
    request_bytes = bytearray(request_body.encode(encoding='UTF-8'))
    return hmac.new(
        signing_bytes,
        request_bytes,
        hashlib.sha256,
    ).hexdigest()
using System;
using System.Security.Cryptography;
using System.Text;

private static string GenerateWebhookSignature(string signingSecret, string requestBody)
{
  byte[] signingSecretBytes = Encoding.UTF8.GetBytes(signingSecret);
  byte[] requestBodyBytes = Encoding.UTF8.GetBytes(requestBody);
  HMACSHA256 hash = new HMACSHA256(signingSecretBytes);
  byte[] hashBytes = hash.ComputeHash(requestBodyBytes);
  return BitConverter.ToString(hashBytes).Replace("-","").ToLower();
}