Skip to main content

Checking webhook signatures

Indent signs the webhook requests sent to your endpoints by including a signature in each event’s X-Indent-Signature and a timestamp in the X-Indent-Timestamp header. This allows you to verify that the events were sent by Indent, not by a third party. You can verify signatures either using our official libraries, or manually using your own solution.

Before you can verify signatures, you need to retrieve your endpoint’s secret from your Dashboard’s webhooks settings. Select a webhook that you want to obtain the secret for, then click the "Show" button.

Indent generates a unique secret key for each endpoint. If you use the same endpoint for both test and live API keys, note that the secret is different for each one. Additionally, if you use multiple endpoints, you must obtain a secret for each one you want to verify signatures on. We recommend creating multiple webhooks in order to test staging vs production.

Official libraries#

import { verify } from '@indent/webhook'
// or use CommonJS
const { verify } from '@indent/webhook'
await verify({
secret: process.env.INDENT_WEBHOOK_SECRET,
headers: req.headers,
body: req.body
})

Verifying signatures manually#

The X-Indent-Signature header included in each signed event along with an X-Indent-Timestamp header, like this:

X-Indent-Signature: c27f187960625ebccc33336030b071dac1d54b1e98d9e27fe5452ee00c935fb0;
X-Indent-Timestamp: 2020-05-01T07:00:00Z

Step 1: Prepare the signed payload#

The signed payload is created by concatenating:

  • The signature version v0
  • The colon character :
  • The timestamp (as a string)
  • The colon character :
  • The actual JSON payload

Like this:

v0:2020-05-01T07:00:00Z:{"events":[{"event":"access/grant","timestamp":"2020-05-01T07:00:00Z"}]}

Step 2: Evaluate the payload signature#

Compute an HMAC with the SHA256 hash function. Use the webhook’s signing secret as the key, and use the signed payload string as the message.

Step 3: Compare the signatures#

Compare the signature (or signatures) in the header to the expected signature. For an equality match, compute the difference between the current timestamp and the received timestamp, then decide if the difference is within your tolerance.

To protect against timing attacks, use a constant-time string comparison to compare the expected signature to each of the received signatures.