These docs are for v1.0.0. Click to read the latest docs for v2.0.0.

Verifying Requests

Request signatures allow your app to verify the authenticity of incoming webhook traffic. These signatures will be provided as an X-Webflow-Signature HTTP header, which Webflow generates by creating a HMAC hash of the request timestamp and body using your OAuth Application's Client Secret as the hash key.

While request validation is not required for receiving Webflow webhook requests, it is highly recommended.

🚧

Signatures are only included in OAuth Apps

Webhooks created via a site's dashboard or with a Site's API Key will not include request signatures. If you would like to utilize request signatures, please regenerate your webhooks using an OAuth application.

Validating Request Signatures

To validate a Webflow webhook request, you'll need to create an HMAC hash using the values of the request's X-Webflow-Timestamp header, the X-Webflow-Signature header, and your OAuth Application's Client Secret.

Request validation is a two steps process:

Validate the Timestamp

Checking the age of the request timestamp included in X-Webflow-Timestamp. If the request is older than 5 minutes, this may indicate a replay attack.

Validate the Request Body

Create a hash from the combination of the request body, a :, and the timestamp.
Number(request_timestamp) + ":" + JSON.stringify(request_body)

Then compare the hash with the X-Webflow-Signature request header.

Node.js Example

Incoming Request Headers

[X-Webflow-Timestamp, 1663849649733]
[X-Webflow-Signature, db37faac5680c551e1860d6cf88c261565c25bdf0c8275d5d71f24ee079bb7ca]

Validation

// Import Node's Crypto module
import crypto from 'crypto';

// Webhook Request Validation
function validateRequestSignature(signature, timestamp, body, consumer_secret){
  // Return false if timestamp is more than 5 minutes old
  if (((Date.now() - Number(timestamp)) / 60000) > 5){
    return false
  };

  // Concatinate the request timestamp header and request body
  const content = Number(request_timestamp) + ":" + JSON.stringify(request_body);

  // Generate an HMAC signature from the timestamp and body
  const hmac = crypto
    .createHmac('sha256', consumer_secret)
    .update(content)
    .digest('hex');

  // Create a Buffers from the generated signature and signature header
  const hmac_buffer = Buffer.from(hmac);
  const signature_buffer = Buffer.from(request_signature);

  // Compare generated signature with signature header checksum and return
  return crypto.timingSafeEqual(hmac_buffer, signature_buffer);
}

// Get request body, timestamp and signature headers
request_body = request.body();
request_timestamp = request.headers['X-Webflow-Timestamp'];
request_signature = request.headers['X-Webflow-Signature'];

// Validate the request signature to ensure this request came from Webflow
if (validateRequestSignature(request_signature, request_timestamp, request_body, consumer_secret)) {
    // Process the request
} else {
    // Reject the request
}

Other Examples

We've provided an example Javascript implementation to the right, but most modern programming languages have modules and tutorials for HMAC validation.