Payfort Return Signature Mismatch For Apple Pay on Web

1.2k views Asked by At

I'm integrating Apple Pay on our website using payfort.

Payfort ask to calculate signature which work fine if input values are string. But the problem is what if value is array.

As shown in following image from there documentation. They require apple_header and apple_paymentMethod field to be List data type. Now how should i calculate the signature in this case since it takes key and value as string. but in our case value is array. (i.e. apple_paymentMethod AND apple_paymentMethod)

I tried these 2 fields using json_encode function.

If i send these 2 fields as string then payfort api return invalid format for field: apple_header. If i send these 2 fields as array then payfort api return Signature Mismatch.

I don't have any idea what am i missing.

Here is my code:

Controller Code:

$parameters = [
            'digital_wallet'        => 'APPLE_PAY',
            'command'               => 'PURCHASE',
            'access_code'           => config('payfort.APPLE_ACCESS_CODE'),
            'merchant_identifier'   => config('payfort.APPLE_MERCHANT_IDENTIFIER'),
            'merchant_reference'    => date( 'Y' ).str_pad($request->iOrderId, 6, 0, STR_PAD_LEFT) . '_' . time(),
            'amount'                => 7000,
            'currency'              => 'SAR',
            'language'              => 'en',
            'customer_email'        => '[email protected]',
            'apple_data'            => $request->token['paymentData']['data'],
            'apple_signature'       => $request->token['paymentData']['signature'],
            
            'apple_header'          => json_encode([
                'apple_transactionId'=> $request->token['paymentData']['header']['transactionId'],
                'apple_ephemeralPublicKey'=> $request->token['paymentData']['header']['ephemeralPublicKey'],
                'apple_publicKeyHash'=> $request->token['paymentData']['header']['publicKeyHash']
            ]),

            'apple_paymentMethod'   => json_encode([
                'apple_displayName'=> $request->token['paymentMethod']['displayName'],
                'apple_network'=> $request->token['paymentMethod']['network'],
                'apple_type'=> $request->token['paymentMethod']['type']
            ]),
         
            'customer_ip'           => $request->ip(),
            'customer_name'         => 'ABC',
            'merchant_extra'        => $request->iOrderId,
            'merchant_extra1'       => $request->order_number,
            'merchant_extra2'       => $request->locale_info,
        ];

        // canculate signature
        $parameters['signature'] = $this->payfortCoreHelpers->calculateSignature($parameters, 'request', true);

        // Add Array or List fields in back to parameters before send
        $parameters['apple_header'] = [
            'apple_transactionId'=> $request->token['paymentData']['header']['transactionId'],
            'apple_ephemeralPublicKey'=> $request->token['paymentData']['header']['ephemeralPublicKey'],
            'apple_publicKeyHash'=> $request->token['paymentData']['header']['publicKeyHash']
        ];
        $parameters['apple_paymentMethod'] = [
            'apple_displayName'=> $request->token['paymentMethod']['displayName'],
            'apple_network'=> $request->token['paymentMethod']['network'],
            'apple_type'=> $request->token['paymentMethod']['type']
        ];
        

calculateSignature function

public function calculateSignature($arrData, $signType = 'request', $isAppleRequest = false)
{
    $shaString = '';
    ksort($arrData);

    foreach ($arrData as $k => $v) {
        $shaString .= "$k=$v";
    }

    $shaString = config('payfort.SHA_REQUEST_PHRASE') . $shaString . config('payfort.SHA_REQUEST_PHRASE');

    $signature = hash(config('payfort.SHA_TYPE'), $shaString);

    return $signature;
}

enter image description here

Payfort Response

{
  "amount": "7000",
  "response_code": "00008",
  "digital_wallet": "APPLE_PAY",
  "signature": "****",
  "merchant_identifier": "****",
  "access_code": "****",
  "customer_ip": "::1",
  "language": "en",
  "command": "PURCHASE",
  "merchant_extra": "****",
  "response_message": "Signature mismatch",
  "merchant_reference": "20201599817035025",
  "customer_email": "[email protected]",
  "merchant_extra1": "1599817035025",
  "merchant_extra2": "SAR",
  "currency": "SAR",
  "customer_name": "ABC",
  "status": "00"
}
2

There are 2 answers

0
adexot On

You might find this link helpful: https://github.com/devinweb/payment/blob/fa595fe60df4dff3c4f2189e37fd64fffdc8421b/src/Traits/Payfort/ApplePay.php#L51

This shows calculateSignature method that generates the signature for your request.

Particularly, line 67 shows that you need to have a comma followed by space between the items in the nested array.

0
Jawad Rana On
ksort($arrData);
        foreach ($arrData as $key => $value) {
            if(is_array($value)){
                $shaSubString = '{';
                foreach ($value as $k => $v) {
                    $shaSubString .= "$k=$v, ";
                }
                $shaSubString = substr($shaSubString, 0, -2).'}';
                $shaString .= "$key=$shaSubString";
            }else{
                $shaString .= "$key=$value";
            }
        }