Reputation: 356
I am trying to post a request for "flex/v1/keys" api and i am trying to mirror the examples CyberSource have on the api page. But i keep getting back {"response":{"rmsg":"Authentication Failed"}}
.
Please can someone assist me i am clueless and been struggling for a while now.
Code for getting headers sorted.
var crypto = require("crypto-js");
var requestHost = 'apitest.cybersource.com';
var merchantId = 'testrest';
var merchantKeyId = '08c94330-f618-42a3-b09d-e1e43be5efda';
var merchantSecretKey = 'yBJxy6LjM2TmcPGu+GaJrHtkke25fPpUX+UY6/L/1tE=';
var resource = "/flex/v1/keys";
//digest
var payload = '{"encryptionType": "None"}';
var data = crypto.enc.Utf8.parse(payload)
var hash = crypto.SHA256(data)
var base64 = crypto.enc.Base64.stringify(hash);
var digest = "SHA-256=" + base64;
pm.globals.set("digest",digest);
//date
var date = new Date(Date.now()).toUTCString();
pm.globals.set("date",date);
//signature
var signatureHeader = "";
signatureHeader += "keyid=\"" + merchantKeyId + "\"";
signatureHeader += ", algorithm=\"HmacSHA256\"";
var headersForPostMethod = "host date (request-target) digest v-c-merchant-id";
signatureHeader += ", headers=\"" + headersForPostMethod + "\"";
var signatureString = 'host: ' + requestHost;
signatureString += '\ndate: ' + new Date(Date.now()).toUTCString();
signatureString += '\n(request-target): ';
var targetUrlForPost = "post " + resource;
signatureString += targetUrlForPost + '\n';
signatureString += 'digest: SHA-256=' + digest + '\n';
signatureString += 'v-c-merchant-id: ' + merchantId;
var dataSigString = crypto.enc.Utf8.parse(signatureString);
var secKey = crypto.enc.Base64.parse(merchantSecretKey);
var hashHmac = CryptoJS.HmacSHA256(dataSigString, secKey)
var base64hashHmac = CryptoJS.enc.Base64.stringify(hashHmac);
signatureHeader += ", signature=\"" + base64hashHmac + "\"";
pm.globals.set("signature",signatureHeader);
My post request i am trying to send.
curl --location --request POST 'https://apitest.cybersource.com/flex/v1/keys' \
--header 'digest: SHA-256=yF79QR9XHmXEMjhnXRIvsaGie/xoTduWMP8kMOUIyVc=' \
--header 'v-c-merchant-id: testrest' \
--header 'date: Fri, 29 May 2020 15:06:42 GMT' \
--header 'host: apitest.cybersource.com' \
--header 'signature: keyid="08c94330-f618-42a3-b09d-e1e43be5efda", algorithm="HmacSHA256", headers="host date (request-target) digest v-c-merchant-id", signature="lnv5/zeUimcef0Dr3VeOyKgOw/cX8Erdb+qaKuSwuug="' \
--header 'profile-id: 93B32398-AD51-4CC2-A682-EA3E93614EB1' \
--header 'Content-Type: application/json' \
--data-raw '{"encryptionType": "None"}'
RESULTS
POST https://apitest.cybersource.com/flex/v1/keys
Request Headers
digest: SHA-256=yF79QR9XHmXEMjhnXRIvsaGie/xoTduWMP8kMOUIyVc=
v-c-merchant-id: testrest
date: Fri, 29 May 2020 14:57:17 GMT
host: apitest.cybersource.com
signature: keyid="08c94330-f618-42a3-b09d-e1e43be5efda", algorithm="HmacSHA256", headers="host date (request-target) digest v-c-merchant-id", signature="cLFxiYvra8KMBOaTB25Ke+gnQh67/MMn9wr0d8PRSm4="
profile-id: 93B32398-AD51-4CC2-A682-EA3E93614EB1
Content-Type: application/json
User-Agent: PostmanRuntime/7.25.0
Accept: */*
Cache-Control: no-cache
Postman-Token: ef33044d-e745-4014-bdd8-d30f659be760
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Length: 27
Request Body
{"encryptionType": "None"}↵
Response Headers
Strict-Transport-Security: max-age=31536000
v-c-correlation-id: 9e9d8293-b909-4fdf-9ae6-9f992e5dca87
content-type: application/json
v-c-response-time: 1590764238
content-length: 45
Response Body
{"response":{"rmsg":"Authentication Failed"}}
Upvotes: 1
Views: 2877
Reputation: 11
I ran into a similar issue, thanks a lot for your insight. I simplified the way to construct the REST authentication in Postman:
As a prerequisite, you have to set "merchantId", "merchantKeyId", "merchantSecretKey" and "restEndPointHost" at "environment" level.
const crypto = require('crypto-js');
const merchantId = pm.environment.get('merchantId');
const merchantKeyId = pm.environment.get('merchantKeyId');
const merchantSecretKey = pm.environment.get('merchantSecretKey');
const requestHost = pm.environment.get('restEndpointHost');
const requestTarget = pm.collectionVariables.replaceIn(pm.request.url.getPath());
const requestMethod= pm.request.method.toLowerCase();
// Request body
const requestBody = pm.variables.replaceIn(pm.request.body.raw);
// Digest
const digest = `SHA-256=${crypto.enc.Base64.stringify(crypto.SHA256(crypto.enc.Utf8.parse(requestBody)))}`;
pm.variables.set("digest", digest);
// Date
const date = new Date(Date.now()).toUTCString();
pm.variables.set("date", date);
// Signature
const string = `host: ${requestHost}\ndate: ${date}\n(request-target): ${requestMethod} ${requestTarget}\ndigest: ${digest}\nv-c-merchant-id: ${merchantId}`;
const signature = `keyid="${merchantKeyId}", algorithm="HmacSHA256", headers="host date (request-target) digest v-c-merchant-id", signature="${CryptoJS.enc.Base64.stringify(CryptoJS.HmacSHA256(crypto.enc.Utf8.parse(string), crypto.enc.Base64.parse(merchantSecretKey)))}"`;
pm.variables.set("signature", signature);
To be put into "Pre-request script" section at "collection" level.
Then for each of your REST requests (inside this collection), in the "Headers" section, you have to add those custom headers:
v-c-merchant-id {{merchantId}}
Date {{date}}
Digest {{digest}}
Signature {{signature}}
Upvotes: 1
Reputation: 356
for anyone encountering this issue i have found my fix and it works now with crypto-js authentication.
Silly mistake from me not building the string up properly. just update the script mentioned in my question with the following.
BROKEN
signatureString += 'digest: SHA-256=' + digest + '\n';
FIX
signatureString += 'digest: ' + digest + '\n';
Upvotes: 3