Skip to content

Check webhook signatures

Confirm webhook events were sent by Moov

Every event Moov sends to a webhook endpoint includes a signature generated through a SHA-512 hash-based message authentication code (HMAC).

This allows you to verify that Moov (and not a third party) sent these events to your service.

To check the signature for a particular webhook, use the signing secret to create a new hash through the steps outlined below. If the hash you created matches the value of the X-Signature header, you know that the event came from Moov. Otherwise, your service can discard the event.

All of the data needed to create the hash, except for the signing secret, is sent in HTTP headers in the POST to the configured webhook endpoint. You can obtain the signing secret for each webhook from the Moov Dashboard.

Steps to check the signature

The headers with values needed to create the hash are:

  • X-Timestamp
  • X-Nonce
  • X-Webhook-ID

Using your favorite programming language, perform the following steps to construct your hash and compare against the event signature:

  1. Get the signing secret from the Moov Dashboard.
  2. Get the header values from the received POST.
  3. Prepare the signed payload. timeStamp + "|" + nonce + "|" + webhookID
  4. Determine the expected signature using the signing secret and the payload from step 3.
  5. Check both signatures for equality.

Let’s look at a pseudo code sample:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
// Step 1
const secret = 'webhook-signing-secret';

// Step 2
const timeStamp = req.headers("X-Timestamp")
const nonce     = req.headers("X-Nonce")
const webhookID = req.headers("X-Webhook-ID")
const signature = req.headers("X-Signature")

// Step 3
const headers = `${timeStamp}|${nonce}|${webhookID}`;

// Step 4
const checkHash = cryptojs.HmacSHA512(headers, secret);

// Step 5
if (signature === checkHash) {
  // The event came from Moov. Process it!
} else {
  // The event didn't come from Moov. 
}
The above code example has been simplified for brevity.
Previous Webhook events