Apple Pay on Web-Integration with Rails-Part 3

Apple Pay Logo

This is the third and last post in this series of blog posts where we have been improving our application to support payments via Apple Pay. All the posts of this series are as follows:

  1. Register Merchant ID, domain, and generate certificates
  2. Create merchant session, show payment modal and authorize payment
  3. Decrypt Apple Pay JSON response

In previous posts, we generated various certificates for Apple Pay and added some code to make the Apple Pay button visible to the users. We were also able to get the success response (JSON) from Apple on successful authorisation of payment by the user.

The JSON response returned by Apple contains the token in encrypted form. Some of the payment gateways accept the encrypted data for creating charges (as they handle decryption on their end) while others need the JSON to be decrypted on your end before passing it to their API. So, based on what payment gateway you are going to use, you can read/skip this post.

The data can be decrypted using the certificates we generated in first post of this series. Lets see how we can do that.

Decrypt Apple Pay JSON response

  1. Sample JSON response
  2. Install gems
  3. Decrypt response

1 Sample JSON response

Let us recap how the JSON response from Apple looked like:

payment = {
  "token"=>{
    "paymentData"=>{
      "version"=>"EC_v1",
      "data"=>"VsVvw2VCOaMa11WYJthb/MpAifih9wk2fqFrrCainB...DmD+S3jo3TFgPktA64e9RtuEm1ream6BQM+5mP",
      "signature"=>"MIAGCSqGSIb3DQEHAqCAMIACAQMEAgEFA...qDDe9FD3HGlD0004rgx50gthVyLZwAAAAAAAA==",
      "header"=>{
        "ephemeralPublicKey"=>"MFkwEwYHKoZIzj0CAQYIKoj0QcDQgA...T+XzfmGFvRs/G2qwgmWY8fKu7p6Ktgxug==",
        "publicKeyHash"=>"AJiEM3d+czut7s1t4QdtRBPjSOxw0D6iWSp1MUdXueM=", 
        "transactionId"=>"f8f0c804922303decba1a8a4f7c503df1a6314e44e8db5ae7eb6b7fe0323513b"
      }
    },
    "paymentMethod"=>{
      "displayName"=>"MasterCard 1471",
      "network"=>"MasterCard",
      "type"=>"debit"
    },
    "transactionIdentifier"=>"F8F0C804922303DECBA1A8A4F7C503DF1A6314E44E8DB5AE7EB6B7FE0323513B"
  }
}

2 Install gems

We are using gems gala and aead for decryption here.

# Gemfile
gem 'gala', '~> 0.3.1'
gem 'aead', git: 'https://github.com/Shopify/aead.git', ref: '340e7718d8bd9c1fcf3c443e32f439436ea2b70d'

Run `bundle install`.

3 Decrypt response

require 'gala'

payment_token = ::Gala::PaymentToken.new(payment['token']['paymentData'])
=> #<Gala::PaymentToken:0x007feb6c73f2d0 @version="EC_v1", @data="VsVvw2VCOaMa11WYJthb/MpAifih9wk2fqPU6FxJRrrCainB...D+S3jo3TFgPktA64e9RtuEm1ream6BQM+5mP", @signature="MIAGCSqGSIb3DQEHAqCAMIACAQExDzANBglghkgBZQMEAgEFA...qDDe9FD3HGlD0004rgx50gthVyLZwAAAAAAAA==", @transaction_id="f8f0c804922303decba1a8a4f7c503df1a6314e44e8db5ae7eb6b7fe0323513b", @ephemeral_public_key="MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgA...T+XzfmGFvRs/G2qwgmWY8fKu7p6Ktgxug==", @public_key_hash="AJiEM3d+czut7s1t4QdtRBPjSOxw0D6iWSp1MUdXueM=", @application_data=nil>

cert = Rails.root.join('path', 'to', 'apple_pay.cer').read
=> "0\x82\u0004t0\x82\u0004\u0019\xA0\u0003\u0002...\xB3\u000F\xF0\b\xAE;\xF1j\u000Fʴ\xC8@\xC7"

pem = Rails.root.join('path', 'to', 'payment_processing_certificate.key.pem').read
=> "Bag Attributes\n    friendlyName: TODO_PAYMENT_CSR_0728\n    localKeyID: 51 61 60 E5 2F 38 ... FB 6E A8 17 DC 4E \nKey Attributes: \n-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEILXPhijAztJ0l4zleKgTy1fSh2undI60AEUKc...+ZwK4YlMSmRkQ9swCKyRdjAs3vU6AXC+F8bA==\n-----END EC PRIVATE KEY-----\n"

data = payment_token.decrypt(cert, pem)
=> "{\"applicationPrimaryAccountNumber\":\"5204242750270010\",\"applicationExpirationDate\":\"190731\",\"currencyCode\":\"392\",\"transactionAmount\":346,\"deviceManufacturerIdentifier\":\"050110030273\",\"paymentDataType\":\"3DSecure\",\"paymentData\":{\"onlinePaymentCryptogram\":\"AK5g1Zu5CPm7AAV8DSTlAoABFA==\"}}"

JSON.parse(data)
=> {"applicationPrimaryAccountNumber"=>"5204242750270010", "applicationExpirationDate"=>"190731", "currencyCode"=>"392", "transactionAmount"=>346, "deviceManufacturerIdentifier"=>"050110030273", "paymentDataType"=>"3DSecure", "paymentData"=>{"onlinePaymentCryptogram"=>"AK5g1Zu5CPm7AAV8DSTlAoABFA=="}}

And we are done. Above is the final decrypted JSON response from Apple.

Hope this series of blog post gives you a single source of documentation to integrate Apple Pay in your Ruby on Rails web applications.

If you have any feedback, please let us know in comments below.

Leave a Reply

Your email address will not be published. Required fields are marked *