I was caught off guard by Authorize.Net's recent retirement of the md5 hash to authenticate their responses to AIM transactions. I'm trying to fix some legacy code to keep our legacy site limping along until we can get the rebuilt site out -- IT WILL NOT RUN the latest Authorize.Net PHP SDK so please do not suggest that in response to this question.
In trying to fix this legacy code, I cannot get the test transactions (or even some test transactions run using live/production credentials) to supply the HMAC-SHA512 hash promised in the Aim Guide in the section titled "Authenticating the Response."
Here's a sample raw response from an AIM transaction:
"1"|"1"|"1"|"This transaction has been approved."|"52R4QE"|"Y"|"40034138508"|"2019-07-0269072"|"Purchase Description Blah Blah Blah"|"99.95"|"CC"|"auth_capture"|"3"|"Joe"|"Test"|"n/a"|"123 Main St."|"Los Angeles"|"CA"|"90026"|"US"|""|""|"joe.test@example.com"|""|""|""|""|""|""|""|""|""|""|""|""|""|""|"P"|"2"|""|""|""|""|""|""|""|""|""|""|"XXXX1111"|"Visa"|""|""|""|""|""|""|""|""|""|""|""|""|""|""|""|""|""
According to the AIM Guide:
"The last field in the response contains the HMAC-SHA512 hash that Authorize.Net generated for the transaction, which can be used to authenticate the response. To use it, construct an HMAC-SHA512 hash..."
This does not appear to be the case at all. Is this HMAC only present for certain types of transacations? Is it not provided by the sandbox gateway? What's the deal? Where is the HMAC-SHA512 hash?
Here is a PHP script which illustrates my problem:
<?php
$now = time();
// AUTOMATICALLY GENERATE AN INVOICE NUMBER
$invoice_number = date('Y', $now) . "-" . date('m', $now) . "-" . date('d', $now) . rand(0,100000);
// Authorize.net credentials
$api_login_id = "<YOUR API-LOGIN-ID-HERE>";
$transaction_key = "<YOUR TRANSACTION KEY HERE>";
$authnet_values = array(
// "x_test_request" => "TRUE",
"x_login" => $api_login_id,
"x_version" => "3.1",
"x_delim_char" => "|",
"x_encap_char" => "\"",
"x_delim_data" => "TRUE",
"x_url" => "FALSE",
"x_type" => "AUTH_CAPTURE",
"x_method" => "CC",
"x_tran_key" => $transaction_key,
"x_relay_response" => "FALSE",
"x_card_num" => "4111111111111111",
"x_exp_date" => "01-2020",
"x_description" => "TEST TRANSACTION " . uniqid(),
"x_amount" => 12.34,
"x_currency_code" => "USD",
"x_cust_id" => 1234,
"x_first_name" => "Joe",
"x_last_name" => "Test",
"x_company" => "",
"x_address" => "123 Main St.",
"x_city" => "Springfield",
"x_state" => "MO",
"x_zip" => "12345",
"x_email" => "Joe.Text@example.com",
"x_invoice_num" => uniqid(),
);
$fields = "";
foreach( $authnet_values as $key => $value ) $fields .= "$key=" . urlencode( $value ) . "&";
// ========== !!! DO THE TRANSACTION !!! ==========
// URL of gateway for cURL to post to
$url = "https://test.authorize.net/gateway/transact.dll";
//$url = "https://secure.authorize.net/gateway/transact.dll";
$ch = curl_init($url)
or die("Couldn't establish connection to payment gateway, code 1");
// set to 0 to eliminate header info from response
curl_setopt($ch, CURLOPT_HEADER, 0)
or die("Couldn't establish connection to payment gateway, code 2");
// Returns response data instead of printing it out directly
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1)
or die("Couldn't establish connection to payment gateway, code 3");
// use HTTP POST to send form data
curl_setopt($ch, CURLOPT_POST, TRUE)
or die("Couldn't establish connection to payment gateway, code 4a");
// supply POST data
curl_setopt($ch, CURLOPT_POSTFIELDS, rtrim( $fields, "& " ))
or die("Couldn't establish connection to payment gateway, code 4b");
// Optionally use an old cert bundle or we face ssl authentication problems
//curl_setopt($ch, CURLOPT_CAINFO, '/var/www/ca-bundle/old-ca-bundle.pem')
// or die("Could not establish connection to payment gateway, code 5");
$resp = curl_exec($ch); //execute post and get results
echo "=== RAW ===\n";
print_r($resp);
echo "=== END RAW ===\n";
$curl_info = curl_getinfo($ch);
$curl_info["curl_error"] = curl_error($ch);
$curl_info["curl_errno"] = curl_errno($ch);
echo "=== CURL_INFO ===\n";
print_r($curl_info);
echo "=== END CURL_INFO ===\n";
curl_close ($ch);
$parsed = str_getcsv($resp, '|');
echo "=== PARSED ===\n";
print_r($parsed);
echo "=== END PARSED ===\n";
Your code works for me:
C:\php\php.exe C:\Users\jconde\.PhpStorm2019.1\config\scratches\scratch.php
=== RAW ===
"1"|"1"|"1"|"This transaction has been approved."|"9FUGIS"|"Y"|"40034159620"|"5d1c987e8d88e"|"TEST TRANSACTION 5d1c987e8d4a6"|"12.34"|"CC"|"auth_capture"|"1234"|"Joe"|"Test"|""|"123 Main St."|"Springfield"|"MO"|"12345"|""|""|""|"Joe.Text@example.com"|""|""|""|""|""|""|""|""|""|""|""|""|""|""|"P"|"2"|""|""|""|""|""|""|""|""|""|""|"XXXX1111"|"Visa"|""|""|""|""|""|""|""|""|""|""|""|""|""|""|""|""|"FALSE"|"194894850DF855D0B801F3691203A98CB2EC6C5C1F71E06917FA699065412664DCD7BC35FE2918937BBAB8DCB460DA9E8741799E455CB1D7CCA6BEFEBA71DCC2"=== END RAW ===
=== CURL_INFO ===
Array
(
[url] => https://test.authorize.net/gateway/transact.dll
[content_type] => text/html
[http_code] => 200
[header_size] => 228
[request_size] => 636
[filetime] => -1
[ssl_verify_result] => 20
[redirect_count] => 0
[total_time] => 0.375
[namelookup_time] => 0.063
[connect_time] => 0.078
[pretransfer_time] => 0.11
[size_upload] => 488
[size_download] => 535
[speed_download] => 1426
[speed_upload] => 1301
[download_content_length] => 535
[upload_content_length] => 488
[starttransfer_time] => 0.375
[redirect_time] => 0
[redirect_url] =>
[primary_ip] => 23.219.20.24
[certinfo] => Array
(
)
[primary_port] => 443
[local_ip] => 10.21.50.28
[local_port] => 57726
[curl_error] =>
[curl_errno] => 0
)
=== END CURL_INFO ===
=== PARSED ===
Array
(
[0] => 1
[1] => 1
[2] => 1
[3] => This transaction has been approved.
[4] => 9FUGIS
[5] => Y
[6] => 40034159620
[7] => 5d1c987e8d88e
[8] => TEST TRANSACTION 5d1c987e8d4a6
[9] => 12.34
[10] => CC
[11] => auth_capture
[12] => 1234
[13] => Joe
[14] => Test
[15] =>
[16] => 123 Main St.
[17] => Springfield
[18] => MO
[19] => 12345
[20] =>
[21] =>
[22] =>
[23] => Joe.Text@example.com
[24] =>
[25] =>
[26] =>
[27] =>
[28] =>
[29] =>
[30] =>
[31] =>
[32] =>
[33] =>
[34] =>
[35] =>
[36] =>
[37] =>
[38] => P
[39] => 2
[40] =>
[41] =>
[42] =>
[43] =>
[44] =>
[45] =>
[46] =>
[47] =>
[48] =>
[49] =>
[50] => XXXX1111
[51] => Visa
[52] =>
[53] =>
[54] =>
[55] =>
[56] =>
[57] =>
[58] =>
[59] =>
[60] =>
[61] =>
[62] =>
[63] =>
[64] =>
[65] =>
[66] =>
[67] =>
[68] => FALSE
[69] => 194894850DF855D0B801F3691203A98CB2EC6C5C1F71E06917FA699065412664DCD7BC35FE2918937BBAB8DCB460DA9E8741799E455CB1D7CCA6BEFEBA71DCC2
)
=== END PARSED ===
Process finished with exit code 0
Make sure you have generated a signature key. Without one a hash will not be calculated for you as the signature key is required to generate it).