Verifying Webhook Authenticity | Parallel Developer Documentation

Webhook Signing and Signature Verification

Parallel can optionally sign all webhook requests with a shared secret key, allowing you to verify that the webhook call was actually made by Parallel and not by a third party. After configuring a webhook with a signing key, we will generate and display a unique Key for the client. The text we show for the key is a Base64-encoded representation of a secret key that will be used to sign any requests sent to your webhook.

To verify a signature, you should first extract the values of two custom headers that will be sent with the request:

  1. Parallel-Timestamp: This contains the Unix timestamp when the request was made
  2. Parallel-Signature: This contains the request signature

The header value with the request signature will be a Base64-encoded (with padding) HMAC SHA256 signature of the concatenation of the timestamp and webhook POST body. This can be represented in pseudocode with:

base64(HMACSHA256(WEBHOOK_KEY, TIMESTAMP_HEADER + BODY)))

Here's a full example in NodeJS showing signature verification:

const crypto = require('crypto')

function isValidSignature(webhookKey, signatureHeader, timestampHeader, body) {

const decodedWebhookKey = Buffer.from(webhookKey, 'base64')

const hmac = crypto.createHmac('sha256', decodedWebhookKey)

const sig = hmac.update(timestampHeader + body).digest('base64')

return Buffer.from(signatureHeader).equals(Buffer.from(sig))

}

// The 'Webhook Key' copied from the Webhook config.
// The value is a Base64-encoded representation of the key used in the HMAC.
const webhookKey = 'fKYatxi3x9lI4Zsn31P1sF238a+WUlv/76sJSodYwEbtA=='

// Value of the 'Parallel-Signature' header in the webhook call
const signatureHeader = 'bmnNmLqONdxl/BP/t14rb71tkSO5EgIPyfvhIdbRJ1o='

// Value of the 'Parallel-Timestamp' header in the webhook call
const timestampHeader = '1669748474'

// Raw POST body in the webhook call
const body = '...'

const result = isValidSignature(webhookKey, signatureHeader, timestampHeader, body)

The timestamp value can be used to mitigate a replay attack, a case where an attacker intercepts a valid payload and its signature and retransmits them. In addition to ensuring the signature is correct, you may also verify the provided timestamp is within the last few seconds to prevent such a replay attack.

info

Parallel's signatures are generated using the padded version of Base64, so you'll want to ensure that your output is Base64 encoded with padding as well before comparing against our signature.