Atomic logo

How to Secure Webhook Endpoints

This guide will walk you through the process of securing your webhook endpoints. To get started you will need the following, both of which can be set up by following both the How to Set Up Webhooks Guide and How to Test Webhook Endpoints Guide:

  1. a live webhook endpoint that is receiving event data
  2. a subscription to at least one webhook event in the Atomic Console pointing to your live webhook endpoint
Note that your webhook endpoint must be completely controlled by you and not set up via a webhook testing service, such as webhook.site, otherwise you will not be able to properly secure the endpoint.

After completing this guide, you will have a webhook endpoint up and running that is securely receiving data from Atomic and rejecting content that is not sent by Atomic.

To secure your webhook endpoint, you need to set up HMAC signature validation. When Atomic sends a webhook event, we include an X-HMAC-Signature-Sha-256 header with the request. This header is an HMAC-SHA256 hash of the request body with one of your API secrets used as the key. By validating the HMAC signature with the correct API secret, you can ensure the request came from Atomic and hasn't been tampered with.

Note that the API secret used to create the HMAC signature is the same secret used to create the user's Access Token which was used to initialize Transact.

The process of validating the HMAC signature is relatively straightforward, though implementation details will differ slightly depending on the method you used to build your webhook endpoint.

  1. Re-create the HMAC signature using the request body and the correct API secret.
  2. Compare the HMAC signature you created with the one included in the X-HMAC-Signature-Sha-256 header. If the values match, proceed to processing the webhook event data and respond with a 2xx response. If they do not, reject the request with a 401 or 403 response.
  3. Follow the steps in the How to Test Webhook Endpoints guide to ensure your endpoint receives data. If the signature validation is working properly, your endpoint will send a 2xx response.

Below you will find an example written in NodeJS with ExpressJS utilizing the middleware pattern.

server.js
const express = require('express');
const app = express();
const port = 3000;

const { verifyAtomicWebhook } = require('./middleware');

app.post('/atomic-webhook', verifyAtomicWebhook, (req, res) => {
  // process webhook data
  // send us a 200 to let us know you received the data
  res.send(200, 'Received webhook data');
});

app.listen(port, () => {
  console.log(`Example app listening at http://localhost:${port}`)
});
middleware.js
const crypto = require('crypto')

exports.verifyAtomicWebhook = (req, res, next) => {
  const hash = crypto
    .createHmac('sha256', 'YOUR_ATOMIC_API_SECRET')
    .update(req.body)
    .digest('hex');

  if (hash === req.header('X-HMAC-Signature-Sha-256')) {
    next();
  } else {
    res.send(401, 'You are not authorized.');
  }
};

For an additional layer of security, you can only allow requests from IPs that belong to Atomic. We publish our allowlist in the Atomic Console.

That's it! You now have a webhook endpoint that is securely receiving webhook events. If you would like to review additional topics regarding webhooks, take a look at these guides: