Apple Pay on the WEB > Requesting Apple Pay Session > "An existing connection was forcibly closed by the remote host "

I have technical issue when I make this step in apple Pay
integration
(Apple Pay on the WEB > Requesting Apple Pay Session):

https://developer.apple.com/documentation/apple_pay_on_the_web/apple_pay_js_api/requesting_an_apple_pay_payment_session


I really don't know what the reason to problem is with the
next error I get from Apple.

I've tried all kinds of things for a whole day but I can't
find the reason.

When I send the Post (detailed in link above), I got very
common and general error (I've tried dozens of things mentioned in Google):

“<WebException WebException="SendFailure | The underlying connection was
closed: An unexpected error occurred on a send.| System.IO.IOException: Unable to read data from the
transport connection: An existing connection was forcibly closed by the remote
host. ---&gt; System.Net.Sockets.SocketException: An existing
connection was forcibly closed by the remote host   ……………………”


Apple is blocking me even though the server I work with is
(probably) suited to all their requirements.

Replies

Have you solve the issue. i have the same problem now
I have the same problem. Have you solve the issue? Please help me!! Thank you

I have technical issue when I make this step in apple Pay integration
(Apple Pay on the WEB > Requesting Apple Pay Session):

Unable to read data from the transport connection: An existing connection was forcibly
closed by the remote host.

Apple is blocking me even though the server I work with is (probably) suited to all
their requirements.

Issues related to transport connection failures, or TLS failures, during the point of requesting a payment session from your server are typically related to issues performing two-way TLS with the Apple Pay Servers.

To debug this, do the following:
  1. Make sure to your Merchant Identity certificate is in the correct format and is being used in a format that your server side APIs expect (in this case it looks like .NET).

  2. If you are having trouble with your server side, go around it and validate your Merchant Identity Certificate and Merchant Domain by using CURL instead. This should tell you if you have a server side issue or not.

  3. Increase the verbosity on your server side logs and test this request to see what additional information is provided here.


Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com
We use the next code to obtain the apple session (but it keeps failing):

ServicePointManager.Expect100Continue = True
System.Net.ServicePointManager.SecurityProtocol = Net.SecurityProtocolType.Tls12

Dim Merchant_ID_Key As String = Server.MapPath("./cert/merchant_id.key")
Dim Merchant_ID_Cert As String = Server.MapPath("./cert/merchant_id.pem")

Dim encoding As ASCIIEncoding = New ASCIIEncoding()
Dim postData As String
postData = "{""merchantIdentifier"":""merchant.com.xxxxxx.www"", ""initiative"":""web"", ""domainName"":""xxxxxx.com"", ""displayName"":""xxxxxx""}"
Dim data() As Byte
data = encoding.GetBytes(postData)

Dim SrvCertificate As System.Security.Cryptography.X509Certificates.X509Certificate2Collection = New System.Security.Cryptography.X509Certificates.X509Certificate2Collection()
SrvCertificate.Import(Merchant_ID_Cert, Merchant_ID_Key, System.Security.Cryptography.X509Certificates.X509KeyStorageFlags.MachineKeySet Or System.Security.Cryptography.X509Certificates.X509KeyStorageFlags.PersistKeySet)

'Prepare web request...
Dim myRequest As HttpWebRequest
myRequest = CType(WebRequest.Create("https://apple-pay-gateway.apple.com/paymentservices/paymentSession "), HttpWebRequest)
myRequest.Method = "POST"
myRequest.ContentType = "application/x-www-form-urlencoded"
myRequest.ContentLength = data.Length
myRequest.ClientCertificates = SrvCertificate

Dim newStream As Stream = myRequest.GetRequestStream()

'Send the data.
newStream.Write(data, 0, data.Length)

'Get the response
Dim myResponse As HttpWebResponse
myResponse = myRequest.GetResponse()



We still get the same error:

System.Net.WebException: The underlying connection was closed: An unexpected error occurred on a send. ---> System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host. ---> System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host


We don't know how to fix it or where in the code the bug is. We don't know what exactly we are doing wrong.

Does anyone have any .NET tutorials on Apple Pay on web?

Please, we would appreciate it if someone could help us to solve it so that we can continue with the integration.

Thank you so much!


@JUANMI_ULK The most common cause of this error is your server side API not working with the Merchant Identity Certificate correctly to perform client authentication (two-way TLS). Make sure that you have this ironed out and that you are performing client authentication correctly here.


Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com

I was able to get this working! The thing that's most important to know is that you CANNOT just import the .cer file from your developer portal into your Windows cert store and start attaching it to your requests. In order to get it to work, I had to:

  1. Create a .pfx file (which will, by nature, contain both the cert and its key) as shown here: https://blog.aclerbois.be/blog/2020/01/09/Generates-a-pfx-for-Apple-Pay
  2. Import the generated .pfx file into my Windows cert store.
  3. Attach the cert to my WebRequestHandler

Here's my C# code. Sorry, you'll have to translate it to VB:

public async Task<ApplePaySession> GetSessionAsync(string validationUrl = null)
        {
            var sessionRequestBody = new ApplePaySessionRequest
            {
                merchantIdentifier = ConfigurationManager.AppSettings["ApplePayMerchantIdentifier"],
                displayName = "DISPLAY NAME",
                initiativeContext = ConfigurationManager.AppSettings["ApplePayInitiativeUrl"]
            };

            var handler = new WebRequestHandler();       
            handler.ClientCertificates.Add(GetCertificate(MerchantIdentityCertThumbprint));            

            var client = new HttpClient(handler);

            var url = !string.IsNullOrWhiteSpace(validationUrl) ? validationUrl : PaymentSessionEndpointUrl;
            var response = await client.PostAsJsonAsync(url, sessionRequestBody);
            var applePaySession = await response.Content.ReadAsAsync<ApplePaySession>();
            return applePaySession;
        }

        private X509Certificate2 GetCertificate(string certThumbprint)
        {
            X509Store userCaStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);

            try
            {
                userCaStore.Open(OpenFlags.ReadOnly);
                X509Certificate2Collection certificatesInStore = userCaStore.Certificates;
                X509Certificate2Collection findResult = certificatesInStore.Find(X509FindType.FindByThumbprint, certThumbprint, false);
                X509Certificate2 clientCertificate = null;
                if (findResult.Count == 1)
                {
                    clientCertificate = findResult[0];
                }
                else
                {
                    throw new Exception("Unable to locate the correct client certificate.");
                }
                return clientCertificate;
            }
            catch
            {
                throw;
            }
            finally
            {
                userCaStore.Close();
            }
        }

I hope this helps! I spent a long time piecing together random posts to get this one done.