Verify Webhook Signature
#
OverviewSunbit provides an option to verify webhook requests sent to your endpoints. Every webhook request will include a signature in the request's header. You can use this signature in your code to make sure the request was actually sent by Sunbit.
Before you start, you will need your webhook's signature. You can find it on the Sunbit developer portal under the Webhook section, the signature will be automatically generated when you set your Webhook endpoint.
Webhooks contain a header called "Sunbit-Signature" with the timestamp and a signature. The timestamp is prefixed by t=
and the signature is prefixed by a scheme. Schemes start with v, followed by an integer. Currently, the only valid signature scheme is v1. Sunbit generates signatures using HMAC with SHA2-256.
Header example:
Sunbit-Signature: t=1565220904,v1=20c75c1180c701ee8a796e81507cfd5c932fc17cf63a4a55566fd38da3a2d3d2
#
Verify Webhook signature#
Step 1: Extract the timestamp and signatures from the headerSplit the header, using the ,
character as the separator, to get a list of elements. Split each element using the =
character as the separator, to get a prefix and value pair.
The value t
represents the timestamp (in seconds), and v1
represents the signature.
#
Step 2: Prepare the signed_payload stringThe signed_payload
string is created by concatenating:
.
#
Step 3: Determine the expected signatureUse the 3 components from Step 2 along with the Sunbit Signature to compute an HMAC with the SHA256 hash function. Depending on the language that you are using this will look something like the following:
secret = 'sunbit webhook signature' // the webhook signature from Sunbit Developers Portaltimestamp = sunbitSignatureHeader.substring(between 't=' and ',')payload = timestamp + "." + requestBodyexpectedSignature = hmacSHA256(payload, secret)signature = sunbitSignatureHeader.substring(after 'v1=')if (signature != expectedSignature) throw error
#
Step 4: Compare the signaturesCompare the signature in the header to the expected signature. For an equality match, compute the difference between the current timestamp and the received timestamp, then decide if the difference is within your tolerance (recommended - up to 5 Min)
#
Examples- JavaScript
const crypto = require('crypto');
//Constantsconst headerRegex = /t=(?<timestamp>\d{10}),v1=(?<signature>[a-f0-9]+)/;const secret = 'DwS3QStMkgKziZxd9NXcvqFkxP4JNA3i';
//Header from request: sunbit-signatureconst header = 't=1643444288,v1=e1bfa98d067faeea521387c8917b71c96e32e1f9028a3b0b2167c4c7408cdacb';
//Read header using Regexconst found = header.match(headerRegex);
//Extract the timestampconst timestamp = found.groups.timestamp;
//Construct payload from webhook bodyconst payload = timestamp + "." + JSON.stringify({ "eventType": "MERCHANT_CREATED", "payload": { "location": "Merchant location", "url": "merchant/application/url", "statusReason": "NONE" } });
//Create HMAC from secret and payloadconst hmac = crypto.createHmac('sha256', secret);const data = hmac.update(payload, 'utf8');const gen_hmac= data.digest('hex');
//Check for validityif(gen_hmac === found.groups.signature){ console.log('Valid signature');} else { console.log('Invalid signature');}
//Printing the output on the consoleconsole.log("hmac : " + gen_hmac);