Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Apple Pay - authorize.net returns error 153 only when live, sandbox works

After searching a lot of articles i couldn't find a solution for my problem.

I have integrated ApplePay button on my site and successfuly made transactions in sandbox mode. I'm using authorize.net php SDK to generate the request. The problems started when i switched to live. The message from authorize.net is "There was an error processing the payment data. Required fields are missing from decrypted data"

Here what i have done:

  1. Changed the payment processing certificate with one from live authorize.net account
  2. Changed the credentials i'm using to process authorize.net payments to the same live account i got the payment process certificate
  3. Use live apple device with real credit card.
  4. I'm using First data Nashville processor as CC processor which support ApplePay

Note that if i switch back to sandbox mode, the transaction passes without issues.

The request and the failed response follows:

Request:

{ 
    "createTransactionRequest":{ 
        "merchantAuthentication":{ 
            "name":"xxxxxxxxx",
            "transactionKey":"xxxxxxxxxxx"
        },
        "clientId":"sdk-php-2.0.0",
        "refId":"ref1575669789",
        "transactionRequest":{ 
            "transactionType":"authOnlyTransaction",
            "amount":"14.08",
            "payment":{ 
                "opaqueData":{ 
                    "dataDescriptor":"COMMON.APPLE.INAPP.PAYMENT",
                    "dataValue":"eyJ2ZXJzaW9u...Q1OSJ9fQ=="
                }
            },
            "order":{ 
                "invoiceNumber":"63059-191206",
                "description":"xxxxxxxxx, xxxxxxxxxxxx v9.0.12 (Order# 63059-191206)"
            },
            "customer":{ 
                "type":"individual",
                "email":""
            },
            "billTo":{ 
                "firstName":"xxxxxxx",
                "lastName":"xxxxxxx",
                "address":"xxxx San Remo Cir ",
                "city":"Vista",
                "state":"CA",
                "zip":"92084",
                "country":"US"
            },
            "retail":{ 
                "marketType":0,
                "deviceType":8
            },
            "transactionSettings":{ 
                "setting":[ 
                    { 
                        "settingName":"duplicateWindow",
                        "settingValue":"60"
                    }
                ]
            }
        }
    }
}

Response:

{
    "transactionResponse":{
        "responseCode":"3",
        "authCode":"",
        "avsResultCode":"P",
        "cvvResultCode":"",
        "cavvResultCode":"",
        "transId":"0",
        "refTransID":"",
        "transHash":"",
        "testRequest":"0",
        "accountNumber":"",
        "accountType":"",
        "errors":[
            {
                "errorCode":"153",
                "errorText":"There was an error processing the payment data. Required fields are missing from decrypted data."
            }
        ],
        "transHashSha2":"",
        "SupplementalDataQualificationIndicator":0
    },
    "refId":"ref1575669789",
    "messages":{
        "resultCode":"Error",
        "message":[
            {
                "code":"E00027",
                "text":"The transaction was unsuccessful."
            }
        ]
    }
}

What am i missing?

EDIT:

Here is the code regarding sending opaqueData from ApplePay

$transactionMode = $cc_authorize_mode == $this->MODE_TEST ? \net\authorize\api\constants\ANetEnvironment::SANDBOX : \net\authorize\api\constants\ANetEnvironment::PRODUCTION;
$merchantAuthentication = new AnetAPI\MerchantAuthenticationType();
$merchantAuthentication->setName($cc_authorize_loginid);
$merchantAuthentication->setTransactionKey($cc_authorize_txnkey);

// Set the transaction's refId
$refId = 'ref' . time();
$phoneNumber = ! empty($co_b_phone) ? $co_b_phone : $co_phone;
$customerEmail = ! empty($co_b_email) ? $co_b_email : $co_email;
$ip = lloader()->getUtilByName('ip')->getClientIp();

// Create order information
$order = new AnetAPI\OrderType();
$order->setInvoiceNumber($order_number);
$order->setDescription($this->getOrderPostedByMessage($id_order, $order_number));

// Set the customer's Bill To address
$customerAddress = new AnetAPI\CustomerAddressType();
$customerAddress->setFirstName($co_ccholder_firstname);
$customerAddress->setLastName($co_ccholder_lastname);
if (! empty($co_b_company)) { $customerAddress->setCompany($co_b_company); }
$customerAddress->setAddress($co_b_address." ".$co_b_address2);
$customerAddress->setCity($co_b_city);
$bState = f_isUSState($co_b_state) ? $STATES_XX[$co_b_state] : $STATES[$co_b_state];
$customerAddress->setState($bState);
$customerAddress->setZip($co_b_zip);
$customerAddress->setCountry($countriesISO2[$co_country]);
$customerAddress->setPhoneNumber($phoneNumber);
$customerAddress->setEmail($customerEmail);

// Set the customer's identifying information
$customerData = new AnetAPI\CustomerDataType();
$customerData->setType("individual");
if ( ! empty($member_row['id'])) { $customerData->setId($member_row['id']); }
$customerData->setEmail($customerEmail);


// Add values for transaction settings
$duplicateWindowSetting = new AnetAPI\SettingType();
$duplicateWindowSetting->setSettingName("duplicateWindow");
$duplicateWindowSetting->setSettingValue("60");

// Create a TransactionRequestType object and add the previous objects to it
$transactionRequestType = new AnetAPI\TransactionRequestType();
$transactionRequestType->setCustomerIP($ip);
$transactionRequestType->setTransactionType($this->api_trtype_map[$transactionType]);
if (empty($this->applePayPaymentData)) {
            // Normal CC request
            // Create the payment data for a credit card
            ...
} else {
    $retail = new AnetAPI\TransRetailInfoType();
    $retail->setMarketType('0');
    $retail->setDeviceType('8');
    $transactionRequestType->setRetail($retail);

    // Apple Pay Token Request
    $op = new AnetAPI\OpaqueDataType();
    $op->setDataDescriptor("COMMON.APPLE.INAPP.PAYMENT");
    $paymentToken = base64_encode($this->applePayPaymentData);
    $op->setDataValue($paymentToken);
    $payment = new AnetAPI\PaymentType();
    $payment->setOpaqueData($op);
}

$transactionRequestType->setAmount($grandTotal);
$transactionRequestType->setOrder($order);
$transactionRequestType->setPayment($payment);
$transactionRequestType->setBillTo($customerAddress);
$transactionRequestType->setCustomer($customerData);
$transactionRequestType->addToTransactionSettings($duplicateWindowSetting);

// Assemble the complete transaction request
$request = new AnetAPI\CreateTransactionRequest();
$request->setMerchantAuthentication($merchantAuthentication);
$request->setRefId($refId);
$request->setTransactionRequest($transactionRequestType);

// Create the controller and get the response
$controller = new AnetController\CreateTransactionController($request);
$response = $controller->executeWithApiResponse($transactionMode);
if ($response != null) {
    if ($response->getMessages()->getResultCode() == "Ok") {
       ...
       if ($tresponse != null && $tresponse->getMessages() != null) {
          ...
          return true;
       } else {
          if ($tresponse->getErrors() != null) {
             ...
          }
       }
        ...
    }
    ...
}

EDIT2:

I added email and phone and ip address in the request with same result. The modified request follows:

{ 
"createTransactionRequest":{ 
    "merchantAuthentication":{ 
        "name":"**********",
        "transactionKey":"***************"
    },
    "clientId":"sdk-php-2.0.0",
    "refId":"ref1576180306",
    "transactionRequest":{ 
        "transactionType":"authOnlyTransaction",
        "amount":"14.08",
        "payment":{ 
            "opaqueData":{ 
                "dataDescriptor":"COMMON.APPLE.INAPP.PAYMENT",
                "dataValue":"eyJ2ZXJzaW9uIj...DFiZiJ9fQ=="
            }
        },
        "order":{ 
            "invoiceNumber":"63117-191212",
            "description":"******************* v9.0.12 (Order# 63117-191212)"
        },
        "customer":{ 
            "type":"individual",
            "email":"*********@gmail.com"
        },
        "billTo":{ 
            "firstName":"Gabe",
            "lastName":"Garcia",
            "address":"********* Cir ",
            "city":"Vista",
            "state":"CA",
            "zip":"92084",
            "country":"US",
            "phoneNumber":"**************",
            "email":"**********@gmail.com"
        },
        "customerIP":"************",
        "retail":{ 
            "marketType":"0",
            "deviceType":"8"
        },
        "transactionSettings":{ 
            "setting":[ 
                { 
                    "settingName":"duplicateWindow",
                    "settingValue":"60"
                }
            ]
        }
    }
}

}

like image 688
bksi Avatar asked Dec 06 '19 23:12

bksi


2 Answers

This is most probably due to a data issue in OpaqueData field which comes from ApplePay side. So my suggestion is to print that token in logfile, then decrypt the same using one of the following libraries to manually check whether all data present there. You can do the same for both the Sandbox environment and Live environment. So you will see any difference in token data.

https://github.com/PayU-EMEA/apple-pay

https://github.com/etsy/applepay-php


This is how it does using etsy applepay-php library.

You'll need a 'Payment Processing Certificate' and a private key from Apple (referred to as merch.cer and priv.p12 below). You can generate these at Apple's Dev Center. You'll also need an example payment token generated on an end-user device and the timestamp at which it was generated. An RSA-encrypted token should look like this:

{
 "data": "<base64>",
 "header": {
     "applicationData": "<hex_optional>"
     "wrappedKey": "<base64>",
     "publicKeyHash": "<base64>",
     "transactionId": "<hex>"
 },
 "signature": "<base64>",
 "version": "RSA_v1"
}

Demo

$ # Copy in your payment processing cert and test token
$ cd examples
$ cp /secret/place/merch.cer .
$ cp /secret/place/token.json .
$
$ # Extract private key from cert
$ openssl pkcs12 -export -nocerts -inkey merch.key -out priv.p12 -password 'pass:'
$
$ # Get intermediate and root certs from Apple
$ wget -O int.cer 'https://www.apple.com/certificateauthority/AppleAAICAG3.cer'
$ wget -O root.cer 'https://www.apple.com/certificateauthority/AppleRootCA-G3.cer'
$
$ # Verify chain of trust
$ openssl x509 -inform DER -in merch.cer -pubkey > pub.pem
$ openssl x509 -inform DER -in root.cer > root.pem
$ openssl x509 -inform DER -in int.cer > int_merch.pem
$ openssl x509 -inform DER -in merch.cer >> int_merch.pem
$ openssl verify -verbose -CAfile root.pem int_merch.pem # should output OK
$
$ # Run demo
$ cd ..
$ php -denable_dl=on -dextension=`pwd`/modules/applepay.so examples/decrypt.php -p <privkey_pass> -c examples/token.json -t <time_of_transaction>
like image 112
DinushaNT Avatar answered Sep 22 '22 18:09

DinushaNT


Please tell me how to set up Apple Pay transactions via Authorize.net in PHP? I'm going to use the sample code provided by the official Authorize.net documentation. You used it too. But I don't understand if this code is enough to do everything? Or does it need to be supplemented with something, for example, JavaScript code? And where can I get the dataValue for the request? They write that it is generated based on the Apple Pay JSON token. But where can I get this token?

like image 0
Виктор Аликин Avatar answered Jan 01 '70 00:01

Виктор Аликин