I have created a Shared Secret Key for HTTP Signature Authentication here When I am trying to use them to process a payment in the CyberSource developers playground it works perfectly and in returns 200 OK response
However, when I am trying to create an invoice using the same credentials here, I always get the following 401 UnAuthorized
{
"submitTimeUtc": "2023-05-25T06:07:10.578Z",
"status": "UNAUTHORIZED",
"reason": "Unauthorized",
"message": "Unauthorized Request"
}
Why and how to solve this issue? Thanks in advance
I have created a service file that can help you,
You can use them for the POST
and GET
both requests
<?php
class CyberSourceService
{
public $request_host;
public $merchant_id;
public $merchant_key_id;
public $merchant_secret_key;
public function __construct()
{
$this->request_host = 'apitest.cybersource.com' // this is sendbox host
$this->merchant_id = 'cyber_source.merchant_id'
$this->merchant_key_id = 'cyber_source.api_key_id'
$this->merchant_secret_key = 'cyber_source.secret_key'
}
protected function generateDigest($requestPayload)
{
$utf8EncodedString = mb_convert_encoding($requestPayload, "UTF-8");
$digestEncode = hash("sha256", $utf8EncodedString, true);
return base64_encode($digestEncode);
}
public function getHttpSignature($resourcePath, $httpMethod = "post", $payload = [])
{
$currentDate = date("D, d M Y G:i:s ") . "GMT";
if ($httpMethod == "post") {
$digest = $this->generateDigest($payload); // Get digest data
$signatureString = "host: " . $this->request_host . "\ndate: " . $currentDate . "\n(request-target): " . $httpMethod . " " . $resourcePath . "\ndigest: SHA-256=" . $digest . "\nv-c-merchant-id: " . $this->merchant_id;
} else {
$signatureString = "host: " . $this->request_host . "\ndate: " . $currentDate . "\n(request-target): " . $httpMethod . " " . $resourcePath . "\nv-c-merchant-id: " . $this->merchant_id;
}
$signatureByteString = mb_convert_encoding($signatureString, "UTF-8");
$decodeKey = base64_decode($this->merchant_secret_key);
$signature = base64_encode(hash_hmac("sha256", $signatureByteString, $decodeKey, true));
$signatureHeader = array(
'keyid="' . $this->merchant_key_id . '"',
'algorithm="HmacSHA256"'
);
if ($httpMethod == "post") {
$signatureHeader = array_merge($signatureHeader, array('headers="host date (request-target) digest v-c-merchant-id"'));
$signatureHeader = array_merge($signatureHeader, array('signature="' . $signature . '"'));
} else {
$signatureHeader = array_merge($signatureHeader, array('headers="host date (request-target) v-c-merchant-id"'));
$signatureHeader = array_merge($signatureHeader, array('signature="' . $signature . '"'));
}
$headers = array(
"Accept: application/hal+json;charset=utf-8",
"Content-Type: application/json;charset=utf-8",
"v-c-merchant-id: " . $this->merchant_id,
"Signature: " . implode(", ", $signatureHeader),
"Host: " . $this->request_host,
"Date: " . $currentDate
);
if ($httpMethod == "post") {
$headers = array_merge($headers, array("Digest: SHA-256=" . $digest));
}
return $headers;
}
public function request($resourcePath, $httpMethod = "post", $payLoad = [])
{
$payLoad = json_encode($payLoad);
$headers = $this->getHttpSignature($resourcePath, $httpMethod, $payLoad);
$url = "https://" . $this->request_host . $resourcePath;
$curl = curl_init();
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
if ($httpMethod == "post") {
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $payLoad);
}
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_HEADER, 1);
curl_setopt($curl, CURLOPT_VERBOSE, 0);
$response = curl_exec($curl);
$http_header_size = curl_getinfo($curl, CURLINFO_HEADER_SIZE);
$http_body = json_decode(substr($response, $http_header_size), true);
return $http_body ?? [];
}
}
GET request
$transactionResponse = (new CyberSourceService())->request("/pts/v2/payments/$paymentID", "get");
POST request
$paymentInformationCardArr = [
"number" => 'card_number',
"expirationMonth" => "expiry_month",
"expirationYear" => "expiry_year",
"securityCode" => "security_code",
"type" => cardType code //https://developer.cybersource.com/library/documentation/dev_guides/Retail_SO_API/html/Topics/app_card_types.htm
$orderInformationAmountDetailsArr = [
"totalAmount" => formatPrice($this->ticket->total),
"currency" => "USD"
];
$orderInformationBillToArr = [
"firstName" => first_name
"lastName" => last_name
"address1" => address1
"address2" => address2
"locality" => city
"administrativeArea" => state
"country" => country
"postalCode" => postal_code
"phoneNumber" => phone_number'
"email" => $this->user->email,
];
$orderPayLoad = [
"clientReferenceInformation" => [
"code" => $this->ticket->booking_no
],
"processingInformation" => [
"commerceIndicator" => "internet",
"capture" => true
],
"orderInformation" => [
"billTo" => $orderInformationBillToArr,
"amountDetails" => $orderInformationAmountDetailsArr
],
"paymentInformation" => [
"card" => $paymentInformationCardArr
]
];
$this->orderResponse = (new CyberSourceService())->request("/pts/v2/payments", "post", $orderPayLoad);