2

Background: I am implementing Apple Pay on the web in our website with Authorize.NET as payment processor. I am using .NET framework 4.8. We have some the initial set-up done like obtaining the merchant Id, adding and verifying the merchant domains for our prod and test websites. We got the merchant identity certificate and installed that on our test servers.

Issue: I am facing the below issue while calling the validation url for obtaining the merchant session object. I followed https://tech.justeattakeaway.com/2016/10/10/bringing-apple-pay-to-the-web/ article for implementation.

enter image description here

The main extracts from the code are below. it is failing at 'httpClient.SendAsync' call. It looks like a TLS issue to me, but I have already set it to 1.2 and our test servers are also enabled with TLS1.2. Hence, I am not sure what exactly I am missing here. Any help will be highly appreciated. Thank you.

var validationURL = "https://apple-pay-gateway.apple.com/paymentservices/startSession";
                if (!Uri.TryCreate(validationURL, UriKind.Absolute, out Uri requestUri))
                {
                    throw new UserInputException("An error occurred while serving your request. Please try again later");
                }

                MerchantCertificate mc = new MerchantCertificate(new ApplePayOptions() { UseCertificateStore = true, MerchantCertificateThumbprint = "‎5cdf3xxxxxxxxx345345" });
                ApplePayClient applePayClient = new ApplePayClient(mc.GetCertificate());
                var extension = applePayClient._certificate.Extensions["1.2.840.113635.100.6.32"];
                var merchantId = System.Text.Encoding.ASCII.GetString(extension.RawData).Substring(2);

                var request = new MerchantSessionRequest()
                {
                    DisplayName = "My Store",
                    Initiative = "web",
                    MerchantIdentifier = merchantId,
                    InitiativeContext = "example.com"
                };

Task<HttpResponseMessage> sessionReq = applePayClient.GetMerchantSessionAsync(requestUri, request);



public async Task<HttpResponseMessage> GetMerchantSessionAsync(Uri requestUri, MerchantSessionRequest request)
        {
            var handler = new HttpClientHandler();
            handler.ClientCertificates.Add(_certificate);

            var httpClient = new HttpClient(handler, true);
            //Set security protocol to TLS 1.2 only (REQUIRED by Apple Pay)
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

            //Post the validation data object to the Apple Pay web service through secure channel
            var requestData = CreateContentRequest<MerchantSessionRequest>(HttpMethod.Post, requestUri, request, ContentType);
            var response = await httpClient.SendAsync(requestData);
            return response;
        }

   private static HttpRequestMessage CreateContentRequest<TReq>(HttpMethod method, Uri requestUri, TReq content, string contentType)
        {
            var r = CreateRequest(method, requestUri);
            r.Content = new StringContent(JsonConvert.SerializeObject(content, JsonSettings), Encoding.UTF8, contentType);
            return r;
        }

        private static HttpRequestMessage CreateRequest(HttpMethod method, Uri requestUri)
        {
            var r = new HttpRequestMessage(method, requestUri);
            r.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue(ContentType));
            return r;
        }

EDIT: The below is the result when I call the same from Postman. I have added the client certificate and configured the apple pay domain in Postman.

enter image description here

DareToExplore
  • 249
  • 4
  • 15
  • 2
    The validation URL comes from the client (it will send either the sandbox or production URL to you) - are you correctly forwarding that on? Are you correctly serializing the JSON payload sent to the Apple Pay servers? Is the certificate you're using the correct certificate for the configured merchant? This is mostly me guessing comparing your snippet to the code in the original blog/repo (I wrote them). It was initially trial and error, as as you've seen, the Apple Pay servers don't return helpful error messages if the authentication fails. – Martin Costello Mar 23 '21 at 08:25
  • Hi @MartinCostello, Thank you for your quick response. I have edited the code to add the JSON serializing code as well. And, yes, I am sending the validation URL from client side only. I skipped here for simplicity and included server side code only. I agree Apple Pay servers do not return any useful messages. The 'Apple Pay Merchant Identity' certificate is the one downloaded from the apple developer site. Is there a way to check if certificate is correctly installed? – DareToExplore Mar 23 '21 at 09:48
  • I tried sending the request from Postman and it gives me BAD_PKCS12_DATA. I googled about this error and found that postman sometimes throws this error even if the certificate is valid. I am not sure how to check this further since I am new to this. I appreciate your help. – DareToExplore Mar 23 '21 at 09:57
  • For the "right" certificate I mostly used the code to check the OIDs (like your snippet has in it). I see you're developing for 4.8, but maybe try running the sample code from the blog post with the same configuration to see if you can get that working. If that works, I guess you can try bisecting its code piece by piece with your .NET Framework version to single out where the issue is. – Martin Costello Mar 23 '21 at 10:09
  • Sorry, but can you elaborate about checking the OIDs part for certificate? I guess you integrated Apple pay on ASP.NET Core 1.0. – DareToExplore Mar 23 '21 at 10:34
  • This bit `_certificate.Extensions["1.2.840.113635.100.6.32"]` - you could inspect the certificate in code to check it's the one you expect to be being used. The initial release of the sample was ASP.NET Core 1.0, but it's been updated over time and currently targets .NET 5.0. – Martin Costello Mar 23 '21 at 12:22
  • @MartinCostello, ok thanks. I will try that. – DareToExplore Mar 23 '21 at 13:26
  • @DareToExplore: Have you had any success with this ? – CharithJ Aug 03 '21 at 01:39
  • No @CharithJ, still not. We got focused on other priority projects and this is on hold. As soon as I resume and able to resolve, I will add the solution here. thank you. – DareToExplore Jan 13 '22 at 20:18

1 Answers1

0

Im pretty sure the problem is in

var merchantId = System.Text.Encoding.ASCII.GetString(extension.RawData).Substring(2);

In your example, merchantId will contain something different than the merchant id registered with Apple. Try to hardcode it to the merchant id registered with Apple and it should work.

See example of the request object at: https://developer.apple.com/documentation/apple_pay_on_the_web/apple_pay_js_api/requesting_an_apple_pay_payment_session