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:
-
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. -
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:
- Python: Explore Keyed-Hashing for Message Authentication.
- Java: Dive into HMAC in Java by baeldung.
- Go: Refer to the crypto/hmac documentation.
This enhanced documentation uses more descriptive subheadings, clearer step-by-step instructions, and optimized phrasing to improve clarity and readability.