The HMAC-SHA256 algorithm must be used to generate a request signature, which is calculated using your accessKeySecret
key.
1. Create a content digest for your request body. The keys within the request body should be ordered alphabetically before the digest is generated.
contentDigest = sha256(stringify(requestBody));
2. Generate the string to sign by combining HTTP method, request content type, date-time in ISO-8601 format (also required in header params), fully qualified request path with query parameters (if any), and the content digest (from step 1) with a newline in between each parameter.
Note: Please follow this specific ordering of parameters.
POST
application/json
2022-08-22T02:29:33.123Z
https://integrations-sandbox.shopback.com/posi-sandbox/v1/instore/order/create
a4c198145e81b2904788cf3bb0385276b15962903b1a0d8de0ccf57909cf38bc
3. Sign this string with your accessKeySecret.
4. Generate hex encoded string from step 3 to generate hmac_signature
5. Attach the HMAC Signature in the Authorization header in this format SB1-HMAC-SHA256 accessKeyId:hmac_signature.
Example Code
const crypto = require('crypto');
const _ = require('lodash')
const ACCESS_KEY_SECRET_EXAMPLE = 'f33679f2ae892fd89ceefc409934e49f';
function createSHA256Digest(sortedBody) {
if (_.isEmpty(sortedBody)) {
return '';
}
const hash = crypto.createHash('sha256');
hash.update(JSON.stringify(sortedBody));
return hash.digest('hex');
}
function createHmacSignature(str, secret) {
const hmac = crypto.createHmac('sha256', secret);
hmac.update(str);
return hmac.digest('hex');
}
function computeRequestSignature(req, secret) {
const { method, pathWithQuery, body, contentType, date } = req;
const contentDigest = createSHA256Digest(body);
const payload = `${method.toUpperCase()}\n${contentType}\n${date}\n${pathWithQuery}\n${contentDigest}`;
return createHmacSignature(payload, secret);
}
function alphabeticallySortBody(body: object) {
return Object.keys(body)
.sort()
.reduce(
(acc, key) => ({
...acc,
[key]: body[key],
}),
{},
);
}
function main() {
// Date should be specified in ISO 8601 UTC. Do not specify the time offset
// '2022-08-15T14:59:47.585Z' ✅
// '2022-08-15T22:59:47.585Z+08' ❌
const date = new Date().toISOString(); // to be used for Header param too.
const body = {
referenceId: '352c530dd7f747161a5e6c990c720bec',
currency: 'THB',
posId: '802c987em7f747269a5e6c260c630kpl',
amount: 1000,
}
const sortedBody = alphabeticallySortBody(body)
// alphabetically-ordered keys in sortedBody
// {
// amount: 1000,
// currency: 'THB',
// referenceId: '352c530dd7f747161a5e6c990c720bec',
// posId: '802c987em7f747269a5e6c260c630kpl',
// }
const req = {
method: 'POST',
pathWithQuery: ' https://integrations-sandbox.shopback.com/posi-sandbox/v1/instore/order/create',
body: sortedBody,
contentType: 'application/json',
date,
};
console.log(
'hmac_signature: ',
computeRequestSignature(req, ACCESS_KEY_SECRET_EXAMPLE),
);
}
main();