Retrieve a webhook request

How to validate webhook calls by using the signingSecret value.

Whenever a webhook is called, a X-Satws-Signature header is sent to help verify it. Syntage generates a signature using a hash-based message authentication code (HMAC) with SHA-256 using the signingSecret as key. To verify the hash you can do the following steps:

Step 1 Extract the timestamp and signature from the header

Split the header, using the , character as the separator. The value for the prefix t corresponds to the timestamp and s corresponds to the signature.

Step 2: Prepare the signed_payload string

The signed_payload string is created by concatenating (without spaces):

  • The timestamp (as a string in Unix format) example: "1656569160"

  • The character . (dot)

  • The actual JSON payload (that is, the request body)

Step 3: Determine the expected signature

Compute an HMAC with the SHA256 hash function. Use the endpoint’s signing secret as the key, and use the signed_payload string as the message.

Step 4: Compare the signatures

Compare the signature (or signatures) in the header to the expected signature. For an equality match, compute the difference between the current timestamp and the received timestamp, then decide if the difference is within your tolerance.
To protect against timing attacks, use a constant-time string comparison to compare the expected signature to each of the received signatures.

Here`s a code example using PHP with a constant-time string:

    function splitString(string $separator, $stringValue): array
    {
      return explode($separator, $stringValue);
    }

    ## X-Satws-Signature
    $xSatSignatureHeader = 't=1656569160,s=527124c570b27b3f268777b2ba96a9bbdc4b0ecde2885f688beda528f39c4e23';

    list($timestamp, $signature) = array_map(function($signatureParam){
    return splitString('=', $signatureParam)[1];
    }, splitString(',', $xSatSignatureHeader));

    $bodyPayload = '{
    "@context": "/contexts/Event",
    "@id": "/events/88a88df8-5c55-44a4-a222-ef9999c999",
    "@type": "Event",
    "id": "88a88df8-5c55-44a4-a222-ef9999c999",
    "type": "credential.updated",
    "source": None,
    "createdAt": "2022-06-29 20:14:09",
    "updatedAt": "2022-06-29 20:14:09"
    }';
    $signingSecret = '320639996d9eee9178bf89d26cdbc23d';

    $hash = hash_hmac('sha256', sprintf('%d.%s', $timestamp, $bodyPayload), $signingSecret);

    print strcmp($hash, $signature);
Language
Authorization
Header
URL
Click Try It! to start a request and see the response here!