I can't seem to be able to get the merchant session validation working with Ruby. Tried HTTParty and RestClient and I'm getting:
OpenSSL::SSL::SSLError (SSL_connect returned=1 errno=0 state=SSLv3 read finished A: sslv3 alert certificate expired):
I tried the same certificate with this node server example, https://github.com/tomdale/apple-pay-merchant-session-server, and it worked fine, so it must be something in my ruby code.
Has anyone managed to get this working?
I was having the same problem. With the help of the example you referenced and the implementation at https://github.com/norfolkmustard/ApplePayJS (see also the discussion about the implementation at https://forums.developer.apple.com/thread/51580) I was able to get it working.
The key for me was passing in the correct certificate (the Apple Pay Merchant Identity certificate) just as Apple provides it and getting the cert key like so:
Once you have your Merchant ID (session) certificate from Apple, import that into keychain.app on your Mac by double-clicking it, right click on the cert in keychain and export the combined private-key and cert as a .p12 file then, in terminal:-
openssl pkcs12 -in your_merchant_identity_cert_name.p12 -out ApplePay.key.pem -nocerts -nodes
After adding the Apple Pay Merchant Identification cert from Apple and the contents of the ApplePay.key.pem
file to an environment variable I was able to construct the following request using Ruby's Net::HTTP class...
class YourControllerName < ApplicationController
def apple_pay_validation
respond_to do |format|
format.json { render json: start_apple_session(params[:url]) } if params[:url].include?('apple.com')
end
end
private
def start_apple_session(url)
uri = URI.parse(url) # the url from event.validationURL
data = {'merchantIdentifier' => "merchant.com.your_site_name", 'domainName' => "your_doamin", 'displayName' => "your_company_name"}
pem = File.read('path/to/your/merchant_id.cer')
key = ENV['APPLE_PAY_MERCHANT_ID_ KEY']
passphrase = 'passphrase set up when exporting certificate in keychain' # Should be an environment variable
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.ssl_version = :TLSv1_2
http.ciphers = ['ECDHE-RSA-AES128-GCM-SHA256']
http.cert = OpenSSL::X509::Certificate.new(pem)
http.key = OpenSSL::PKey::RSA.new(key, passphrase)
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
request = Net::HTTP::Post.new(uri.request_uri, 'Content-Type' => 'application/json')
request.body = data.to_json
response = http.request(request)
response.body
end
end
This was called from my performValidation
function (modified from the ApplePayJS repo listed above) which looks like this..
performValidation = (valURL) ->
new Promise((resolve, reject) ->
xhr = new XMLHttpRequest
xhr.open 'GET', '/your_controller_name/apple_pay_validation?url=' + valURL
xhr.onerror = reject
xhr.onload = ->
data = JSON.parse(@responseText)
resolve data
xhr.send()
)
Hopefully that helps save someone some time and gray hairs!