Securing Webhook Requests

You probably want to protect your webhook against malicious behaviors such as man-in-the-middle and replay attacks. Making sure that events originate from Zeplin, and your webhook receives them almost immediately is a good start.

You can verify that a request has originated from Zeplin following the steps below:

  1. Verify the request has a valid signature (Zeplin-Signature header)
  2. Ensure the request is not too old (Zeplin-Delivery-Timestamp header)

Verifying a signature

Zeplin signs the webhook events using the secret of your webhook and includes the signature in each request (Zeplin-Signature header). The signature is hex digest of a hash computed using HMAC with SHA-256.

The signed payload is obtained by concatenating delivery timestamp (Zeplin-Delivery-Timestamp header), '.' character, and the JSON payload sent in the request body.

The following code snippets show how to generate from the payload:

const crypto = require("crypto");

const secret = "...";
const request = {
  headers: {},
  body: {}

const timestamp = request.headers["zeplin-delivery-timestamp"];
const requestBody = request.body;
const signedPayload = `${timestamp}.${requestBody}`;

const hmac = crypto.createHmac("sha256", secret);

const signature = hmac.digest("hex");

Ensuring valid timestamp

Make sure that you receive the payload within a particular time window (e.g., 5 minutes) after Zeplin sends it. To determine this, you can safely compare the delivery timestamp (Zeplin-Delivery-Timestamp header) with the current timestamp.

Whitelisting IP addresses

All webhook requests will originate from the following IP address: