MrBowie20
MrBowie20

Reputation: 356

Need some assistance with CyberSource authentication please

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

Answers (2)

David ROBIN
David ROBIN

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

MrBowie20
MrBowie20

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

Related Questions