Request Signatures

Safeguard the authenticity of incoming webhook traffic to your app using request signatures.

Webflow provides these signatures in the X-Webflow-Signature HTTP header. They are generated by hashing the request timestamp and body through HMAC with your OAuth Application's Client Secret as the hashing key.

📌 Note: While it's optional to validate webhook requests, it's strongly advised for improved security.

🚧

Attention: Only OAuth Apps carry these signatures.

Webhooks originating from a site dashboard or via a Site's API Key won't have request signatures. To benefit from this security feature, create your webhooks through an OAuth application.

How to Validate Request Signatures

Ensure the legitimacy of a Webflow webhook request by generating an HMAC hash. This uses values from the request's X-Webflow-Timestamp and X-Webflow-Signature headers, alongside your OAuth Application's Client Secret.

The Validation Procedure:

  1. Timestamp Verification:

    Analyze the request timestamp found in the X-Webflow-Timestamp header. A request exceeding a 5-minute age could signify a potential replay attack.

  2. Request Body Verification:

    Construct a hash by merging the request body and a : separator with the timestamp.
    Number(request_timestamp) + ":" + JSON.stringify(request_body)

    Then, match this hash against the X-Webflow-Signature header of the request.

Node.js Implementation

Given Request Headers:

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

Validation Code:

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

function validateRequestSignature(signature, timestamp, body, consumer_secret) {
  // Dismiss if timestamp exceeds 5 minutes
  if (((Date.now() - Number(timestamp)) / 60000) > 5){
    return false;
  }

  // Merge the request timestamp and body
  const content = Number(timestamp) + ":" + JSON.stringify(body);

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

  // Transform the derived signature and the header signature into Buffers
  const hmacBuffer = Buffer.from(hmac);
  const signatureBuffer = Buffer.from(signature);

  // Validate if the derived signature matches the header's and return
  return crypto.timingSafeEqual(hmacBuffer, signatureBuffer);
}

// Extract request body, timestamp, and signature headers
const requestBody = request.body();
const requestTimestamp = request.headers['X-Webflow-Timestamp'];
const requestSignature = request.headers['X-Webflow-Signature'];

// Confirm request's authenticity via its signature
if (validateRequestSignature(requestSignature, requestTimestamp, requestBody, consumer_secret)) {
    // Process this verified request
} else {
    // Decline this suspicious request
}

Alternative Implementations

While we presented a JavaScript version, most contemporary languages offer tools and guides for HMAC validation:


This enhanced documentation uses more descriptive subheadings, clearer step-by-step instructions, and optimized phrasing to improve clarity and readability.