Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Apple Pay and Swift how do I send PKPaymentToken to server

Using Swift 3 I'm implementing Apple Pay in my app and trying to send PKPaymentToken which I receive in paymentAuthorizationViewController to bank's API to process payment but without success. The data which I send is always rejected.

Bank support suggests me to send the whole payment.token instead of payment.token.PaymentData but I don't how can I do that cause payment.token is the instance of PKPaymentToken and as I know cannot be converted to string or encoded to base64.

What is the correct way to send the token?

   func paymentAuthorizationViewController(_ controller: PKPaymentAuthorizationViewController, didAuthorizePayment payment: PKPayment, completion: @escaping ((PKPaymentAuthorizationStatus) -> Void)) {
        self.processPayment(payment: payment, completion: completion)
    }

    func processPayment(payment: PKPayment, completion: @escaping ((PKPaymentAuthorizationStatus) -> Void)) {

        print("Payment token: \(payment.token)")

        let paymentData=String(data: payment.token.paymentData.base64EncodedData(), encoding: .utf8)

        var request = URLRequest(url: URL(string: "https://bankapi.com/method")!)
        request.httpMethod = "POST"
        let postString = "orderid=\(orderid)&token=\(String(describing: paymentData))&amount=\(price)"
        print("POST: \(postString)")
        request.httpBody = postString.data(using: .utf8)

        let task = URLSession.shared.dataTask(with: request) { data, response, error in
            guard let data = data, error == nil else {                                                 // check for fundamental networking error
                print("error=\(String(describing: error))")
                return
            }

            if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 {           // check for http errors
                print("statusCode should be 200, but is \(httpStatus.statusCode)")
                print("response = \(String(describing: response))")
            }

            let responseString = String(data: data, encoding: .utf8)
            print("responseString = \(String(describing: responseString))")
            //@TODO check response is failure or success
            //completion(PKPaymentAuthorizationStatus.failure)
        }
        task.resume()
    }

upd. bank service provided me an example in Objective C. I now try to reproduce it in Swift.

like image 426
moogeek Avatar asked Jun 16 '17 11:06

moogeek


People also ask

How do I decrypt Apple Pay token?

To decrypt the token, import the . pem files and create a new PaymentToken with the token from Apple Pay. Then decrypt using the keys. You can then use those decrypted values with your payment processor of choice (Stripe, Braintree, et al) to process payments from Apple Pay.

Does Apple Pay token expire?

The payment processing certificate is used to encrypt the Apple Pay token. The payment processing certificate is valid for 25 months from activation. If you do not replace the CSR and activate the new certificate prior to the expiration date, all Apple Pay transactions will fail.


1 Answers

Ok there is now clear for me.

let paymentDataDictionary: [AnyHashable: Any]? = try? JSONSerialization.jsonObject(with: payment.token.paymentData, options: .mutableContainers) as! [AnyHashable : Any]
var paymentType: String = "debit"

var paymentMethodDictionary: [AnyHashable: Any] = ["network": "", "type": paymentType, "displayName": ""]

if #available(iOS 9.0, *) {
    paymentMethodDictionary = ["network": payment.token.paymentMethod.network ?? "", "type": paymentType, "displayName": payment.token.paymentMethod.displayName ?? ""]

    switch payment.token.paymentMethod.type {
        case .debit:
            paymentType = "debit"
        case .credit:
            paymentType = "credit"
        case .store:
            paymentType = "store"
        case .prepaid:
            paymentType = "prepaid"
        default:
            paymentType = "unknown"
        }
}

let cryptogramDictionary: [AnyHashable: Any] = ["paymentData": paymentDataDictionary ?? "", "transactionIdentifier": payment.token.transactionIdentifier, "paymentMethod": paymentMethodDictionary]
let cardCryptogramPacketDictionary: [AnyHashable: Any] = cryptogramDictionary
let cardCryptogramPacketData: Data? = try? JSONSerialization.data(withJSONObject: cardCryptogramPacketDictionary, options: [])

// in cardCryptogramPacketString we now have all necessary data which demand most of bank gateways to process the payment

let cardCryptogramPacketString = String(describing: cardCryptogramPacketData)
like image 143
moogeek Avatar answered Sep 20 '22 00:09

moogeek