b2b-commerce-on-lightning-quickstart
b2b-commerce-on-lightning-quickstart copied to clipboard
Payeezy Integration results in 403
Using the supplied example for Payeezy and creating a new account in Payeezy to use the apiKey and merchant token respectively results in the following response:
{
"code": "403",
"message": "HMAC validation Failure"
}
Looking at the docs seems the following header values are missing:
nonce
timestamp
Authorization (HMAC that is failing to verify)
Create an HMAC you need the same body information inside of your header encode. I passed the card number and cvv inside additional data so that I could access it inside of my header and build my body properly. This is not an ideal solution. Salesforce/B2B needs to allow for access of the payment data merge fields inside of the header for gateway implementations like this.
/**
* Function to set authorization headers in a request
* Use this to add authorization parameters required for the request
*/
protected void setAuthorizationHeaders(commercepayments.PaymentMethodTokenizationRequest tokenizationRequest, HttpRequest req){
req.setHeader('Content-Type', 'application/json');
//Username and password stored in the named credential that is linked with the payment gateway record
String apiKey = 'apiKey';
req.setHeader('apikey',apiKey); //'{!$Credential.Username}');
String token = 'token';
req.setHeader('token',token); //'{!$Credential.Password}');
String nonce = generateNonce();
req.setHeader('nonce', nonce);
String timestamp = generateTimestampInMilliseconds();
req.setHeader('timestamp', timestamp);
String payload = mergePayloadFields(req.getBody(),(Map<String, String>) tokenizationRequest.additionalData);
String apiSecret = 'apiSecret';
req.setHeader('Authorization', generateHMAC(apiKey,nonce,timestamp,token,payload,apiSecret));
}
/*
Find and replace values in request payload to be transferred to encoded in the header
*/
private String mergePayloadFields(String payload, Map<String, String> additionalData){
for (String key : additionalData.keySet()){
if (payload.contains(key)){
payload = payload.replace(key,additionalData.get(key));
}
}
System.debug(payload);
return payload;
}
private String generateNonce(){
String hashString = '1000' + String.valueOf(Datetime.now().formatGmt('yyyy-MM-dd HH:mm:ss.SSS'));
Blob hash = Crypto.generateDigest('MD5', Blob.valueOf(hashString));
String hexDigest = EncodingUtil.convertToHex(hash);
return hexDigest;
}
private String generateTimestampInMilliseconds(){
return String.valueOf(Datetime.now().getTime());
}
private String generateHMAC(String apiKey, String nonce, String timestamp, String token, String payload, String apiSecret){
String data = apiKey + nonce + timestamp + token + payload;
Blob privateKeyBlob = Blob.valueOf(apiSecret);
Blob urlBlob = Blob.valueOf(data);
Blob signatureBlob = Crypto.generateMac('HmacSHA256', urlBlob, privateKeyBlob);
String str=EncodingUtil.convertToHex(signatureBlob);
System.debug(str);
Blob b=Blob.valueOf(str);
String hmac = EncodingUtil.base64Encode(b);
System.debug('signature is : ' +hmac);
return hmac;
}