How do I validate external webhooks signature received from JourneyApps

I’ve set up an external webhook in the data model and also set a URL to receive the payload from JourneyApps, how do I verify the request on my API server using the signature in the payload and the secret shown in the backend?

There are two fields included in the headers for the POST request generated by JourneyApps and received by your server.

  1. X-Journey-Signature (my personal favorite).
  2. X-Journey-Signature-Rsa-Sha256

These signatures are documented here.

1. X-Journey-Signature

Your web server calculates an HMAC of the payload and a pre-shared secret key. The secret key can be obtained by:

  1. Opening your deployment’s databrowser and navigating to “Manage Webhooks” (you may need to elevate your permissions).
  2. Under “User hooks”, locate the webhook you have in mind
  3. The Secret is located on the right, click on the eyecon to reveal it

Now to calculate the HMAC, you use the raw body of the POST request as the message, in conjunction with the secret.

I’ve included a NodeJS snippet below to get you started.

//ref: https://nodejs.org/api/crypto.html#class-hmac
const crypto = require('crypto');

const hmac = crypto.createHmac('sha256', 'KEY_FROM_STEP_3_ABOVE');

hmac.on('readable', () => {
    // Only one element is going to be produced by the
    // hash stream.
    const data = hmac.read();
    if (data) {
        console.log(data.toString('hex'));
    }
});

let rawbody = {"event":"asset_ready","server":"https://run-testing-us.journeyapps.com","app":"6227b633b8683c00084cf4ed","app_id":"6227b6069983d600076e3af5","account_id":"6227b633b8683c00084cf4ed","sequence":7072864452705518000,"operation":"create","object":{"id":"8ab9480b-fb01-4114-9e5a-1c2554823627","type":"asset","updated_at":"2022-03-08T22:46:23Z","make":"Apple"}}

hmac.write(JSON.stringify(rawbody));
hmac.end();

Some notes:

  1. In this example, rawbody is a static value, whereas you’ll want to obtain this dynamically from your web framework (express, ASP.NET Web API, etc).
  2. Don’t hardcode secrets into source code, this snippet is for reference purposes only
  3. The values in sequence are large numbers, so make sure you’re using big ints / doubles / similar. Something like json-bigint is required for JavaScript. Take care when testing with services such as requestbin, since they often truncate/round these values!

2. X-Journey-Signature-Rsa-Sha256

This method uses PKI and doesn’t require a pre-shared secret. You load the global JourneyApps Webhook cert from disk (or import it as an env variable etc), and then use an RSA signature verification function (e.g. NodeJS verify or .NET VerifyHash) against the value in the request header. Let me know if you’d prefer this method and I can help you out.

2 Likes