Webhook Verification Process

Introduction

When receiving webhooks from Editframe, it is best practice to verify the signature of the incoming request. This ensures that the webhook is authentic and is not being sent by a third party pretending to be Editframe.

This is crucial because your webhook endpoint might be a public endpoint that is accessible to anyone.

This example will show how to verify the signature with node.js and the built-in crypto module. You can use any language that supports similar cryptographic functions, which should be most languages. If you would like more help in this or any other programming language please contact us directly and we will do our best to help you.

Prerequisites

  • Node.js and npm installed
  • crypto module (built-in Node.js module)
  • Environment variable EF_WEBHOOK_SECRET set with the webhook secret

Webhook Verification Steps

1. Receiving the Webhook

The application sets up a POST endpoint at the root (/) to receive incoming webhook events.

app.post('/', (req, res) => {
  // Webhook handling logic
});

2. Extracting the Signature

The webhook signature is expected to be in the X-Webhook-Signature header of the incoming request.

const signature = req.headers['x-webhook-signature'];

3. Calculating the Hash

The application calculates a hash using the following steps:

a. Retrieve the webhook secret from the environment variable:

const secret = process.env.EF_WEBHOOK_SECRET;

b. Create an HMAC (Hash-based Message Authentication Code) using SHA-256:

const hash = crypto.createHmac('sha256', secret)
  .update(await req.text())
  .digest('hex');

// If you are unable to access the raw text of the request body, you should be
// able to re-serialize into JSON and verify that. However, this will require that
// the object is not re-ordered or modified from the original object.

// For example, if the request body is a JSON object, you can do the following:
const body = await req.json();
const hash = crypto.createHmac('sha256', secret)
  .update(JSON.stringify(body))
  .digest('hex');

// Note that no indentation has been added to the JSON object. It must be a 
// 100% bit-for-bit match of the original body text.

4. Comparing the Signature

The calculated hash is compared with the received signature:

if (hash !== signature) {
  res.status(401).send('Invalid signature');
  return;
}

5. Handling the Result

  • If the signatures match, the event is considered valid, and the application responds with a 200 status code.
  • If the signatures don't match, the application responds with a 401 status code, indicating an invalid signature.
  • In case of any errors during the process, the application responds with a 500 status code.

Security Considerations

  • The webhook secret (EF_WEBHOOK_SECRET) should be kept secure and not exposed in the codebase.
  • Always use HTTPS for webhook endpoints to ensure the security of the transmitted data.