Generating A HMAC Signature For A Delivery
This article shows a step by step example for how you can use a transform script in a delivery to sign the delivery with a HMAC signature, as per the example integrations requirements.
In our scenario - we have a buyer that requires a few different headers:
- X-Timestamp: Unix timestamp in seconds
- X-Signature: HMAC calculated from TIMESTAMP.JSON_PAYLOAD
- X-Request-Id: Random UUID
We can achieve adding these three headers to the outbound payload with a transform script, however we first need a delivery set up with the valid payload structure that the buyer's endpoint wants to accept, as we need to replicate that payload inside the transform script.
Setting up the Delivery
Set up a Direct Post - HTTP JSON delivery pointing to the buyer's endpoint.
In the payload builder, configure the payload how the buyer requires it to be structured.
{
"schema_version": "1.0",
"external_lead_id": "BUYERNAME-LEAD-20000000-[leadid]",
"customer_name": "[firstname] [lastname]",
"first_name": "[firstname]",
"last_name": "[lastname]",
"mobile": "[phone1]",
"email": "[email]",
"number_of_products": "[data1]",
"date_of_birth": "[dob]",
"source_data": {
"lead_source": "Source Name",
"product": "Product Name"
}
}
An important thing to note with HMAC signed deliveries is that all the extra whitespace you can see in the finished payload above needs to be removed - you can ask an AI to do this so your payload would need to look like the below instead. Ensure you leave the payload with the whitespace removed and do not "Beautify" the payload as this will break the HMAC signing.
{"schema_version":"1.0","external_lead_id":"BUYERNAME-LEAD-20000000-[leadid]","customer_name":"[firstname] [lastname]","first_name":"[firstname]","last_name":"[lastname]","mobile":"[phone1]","email":"[email]","number_of_products":"[data1]","date_of_birth":"[dob]","source_data":{"lead_source":"Source Name","product":"Product Name"}}
Configure a successful remote system response as per the buyer's integration guide so you can save the delivery and move onto the transform script step.
Setting up the Transform Script
You can create transform scripts by going to "Tech Hub" -> "Transform Scripts" and clicking "+ Add New Script".
Below is the script that will be used for this delivery - the buyer should have sent over a hmacsecret value.
The exact payload used has been re-created in the script to be used in the HMAC signature and the script will output the three headers:
- X-Timestamp: Unix timestamp in seconds
- X-Signature: HMAC calculated from TIMESTAMP.JSON_PAYLOAD
-
X-Request-Id: Random UUID
var main = function(data, ctx) {
var crypto = require('crypto');
var hmacSecret = 'ThisIsAnHMACSecretValue';
if (!ctx.hasOwnProperty('headers') || !Array.isArray(ctx.headers)) {
ctx.headers = [];
}
if (!ctx.hasOwnProperty('extraOptions') || ctx.extraOptions == null) {
ctx.extraOptions = {};
}
var getValue = function(mappedName, leadByteName) {
if (
data != null &&
data.hasOwnProperty(mappedName) &&
data[mappedName] != null
) {
return data[mappedName];
}
if (
data != null &&
data.hasOwnProperty(leadByteName) &&
data[leadByteName] != null
) {
return data[leadByteName];
}
return '';
};
var firstName = String(getValue('first_name', 'firstname'));
var lastName = String(getValue('last_name', 'lastname'));
var leadId = String(getValue('external_lead_id', 'leadid'));
var payload = {
'schema_version': '1.0',
'external_lead_id': 'BUYERNAME-LEAD-20000000-' + leadId,
'customer_name': (firstName + ' ' + lastName).trim(),
'first_name': firstName,
'last_name': lastName,
'mobile': String(getValue('mobile', 'phone1')),
'email': String(getValue('email', 'email')),
'number_of_products': String(
getValue('number_of_products', 'data1')
),
'date_of_birth': String(
getValue('date_of_birth', 'dob')
),
'source_data': {
'lead_source': 'Source Name',
'product': 'Product Name'
}
};
var requestBody = JSON.stringify(payload);
var timestamp = Math.floor(Date.now() / 1000).toString();
var requestId = crypto.randomUUID();
var stringToSign = timestamp + '.' + requestBody;
var signature = crypto
.createHmac('sha256', hmacSecret)
.update(stringToSign, 'utf8')
.digest('hex');
ctx.extraOptions.request = requestBody;
ctx.headers.push('X-Timestamp: ' + timestamp);
ctx.headers.push('X-Signature: ' + signature);
ctx.headers.push('X-Request-Id: ' + requestId);
return {
'data': data,
'ctx': ctx
};
};
TESTING DATA
var data = {
"firstname": "David",
"lastname": "Smith",
"phone1": "07415103842",
"postcode": "CH48BU",
"leadid": "12345",
"email": "leadbytetesting@gmail.com",
"data1": "5",
"dob": "22/01/1980"
};
Testing the script results in:
Array
(
[data] => Array
(
[firstname] => David
[lastname] => Smith
[phone1] => 07415103842
[postcode] => CH48BU
[leadid] => 12345
[email] => leadbytetesting@gmail.com
[data1] => 5
[dob] => 22/01/1980
)
[ctx] => Array
(
[headers] => Array
(
[0] => X-Timestamp: 1789631948
[1] => X-Signature: d105239eed77b7c56d1bca8236c8ac2b5e51329dc7afa10a412f9ad5605429f0
[2] => X-Request-Id: b62928ab-df8d-4c26-abed-b1e421fa1a2a
)
[extraOptions] => Array
(
[request] => {"schema_version":"1.0","external_lead_id":"BUYERNAME-LEAD-20000000-12345","customer_name":"David Smith","first_name":"David","last_name":"Smith","mobile":"07415103842","email":"leadbytetesting@gmail.com","number_of_products":"5","date_of_birth":"22/01/1980","source_data":{"lead_source":"Source Name","product":"Product Name"}}
)
)
)
Save the script and then re-open your delivery from before - go to the advanced settings of the delivery and select the newly created transform script.
Now test the delivery to the endpoint - if the HMAC signature is valid you should see a success response, if the HMAC signature is not valid the endpoint will likely response to tell you so.
Testing my delivery outputs the below:
https://niall.requestcatcher.com/
{"schema_version":"1.0","external_lead_id":"BUYERNAME-LEAD-20000000-12345","customer_name":"David Smith","first_name":"David","last_name":"Smith","mobile":"07415103842","email":"leadbytetesting@gmail.com","number_of_products":"5","date_of_birth":"22\/01\/1980","source_data":{"lead_source":"Source Name","product":"Product Name"}}
Headers:
Array
(
[0] => X-Timestamp: 1789632279
[1] => X-Signature: 073f75d76401f3c78d7b101484b00b05828498f99999f37ad9ebe09e06334e6e
[2] => X-Request-Id: b3ba43c7-bb7e-40e1-8a3f-3eefea601683
)
If you run into any issues at all or need any guidance, please raise a ticket with support.
Comments