Unable to get any response from the apple pay - This resource came from a local override

I am integrating the apple pay and following the payment request api!
According to the documentation
(https://developer.apple.com/documentation/apple_pay_on_the_web/apple_pay_js_api/requesting_an_apple_pay_payment_session)

cert: merchIdentityCert and key: merchIdentityCert both are the same. I append my merchantIdentityCertificate.pem to both cert and key.

Code Block
const options= {
url: endpointURL,
cert: merchIdentityCert,
key: merchIdentityCert,
method: 'post',
body:{
merchantIdentifier: "merchant.com.example.mystore",
displayName: "MyStore",
initiative: "web",
initiativeContext: "mystore.example.com"
},
json: true,
}

But, Unable to get any response from the apple pay servers. After my request it is throwing an error and safari is displaying a message as “This resource came from a local override”

Code:
Code Block
const merchIdentityCert = fs.readFileSync("./merchIdentityCert.pem")
const httpsAgent = new https.Agent({
cert: merchIdentityCert,
key: merchIdentityCert,
maxVersion: "TLSv1.2",
minVersion: "TLSv1.2"
})
const post = (url, body) => {
logger.info({ message: "apple pay START", url, body })
fetch(url, {
body: JSON.stringify(body),
method: "POST",
agent: httpsAgent
}).then(resp => {
logger.info({ message: "apple pay SUCCESS", resp })
return resp
}).catch((error) => {
logger.info({ message: "apple pay ERROR", error })
return error
})
}

Logs:

message: "apple pay START", url:
"https://-pay-gateway-cert.apple.com/paymentservices/startSession", body: {"merchantIdentifier":"***.*.****","displayName":"Test
Pay","initiative":"web","initiativeContext":"
*-*-**.****."}


message: "apple pay ERROR", error: {}

I am using a node-fetch library. My web app and node app deployed in AWS servers. I have fulfilled server setup and environment setup requirements with certificates.
[https://developer.apple.com/documentation/apple_pay_on_the_web/setting_up_your_server]

Does anyone have an idea about this?

Accepted Reply

According to the documentation
cert: merchIdentityCert and key: merchIdentityCert both are the same

merchIdentityCert is added to both of the cert and key fields in the example but these values are not meant to be the same. For example, a Merchant Identity is a p12, or a PKCS12 that contains the Merchant Certificate and a Private Key that was created when you generated a CSR to request your Merchant Certificate. This is a Merchant Identity. Knowing that, you can use the key and the certificate in the way that is being displayed if you have a PEM file that contains both assets. You can also use this file with other server side APIs, but the goal of using a Merchant Identity is to identify yourself as a Merchant and perform client authentication.

As for your issue it is very strange that you would not be able to get a response from the servers at all. I would check that you are using the correct URL and request Payload.


Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com

Replies

According to the documentation
cert: merchIdentityCert and key: merchIdentityCert both are the same

merchIdentityCert is added to both of the cert and key fields in the example but these values are not meant to be the same. For example, a Merchant Identity is a p12, or a PKCS12 that contains the Merchant Certificate and a Private Key that was created when you generated a CSR to request your Merchant Certificate. This is a Merchant Identity. Knowing that, you can use the key and the certificate in the way that is being displayed if you have a PEM file that contains both assets. You can also use this file with other server side APIs, but the goal of using a Merchant Identity is to identify yourself as a Merchant and perform client authentication.

As for your issue it is very strange that you would not be able to get a response from the servers at all. I would check that you are using the correct URL and request Payload.


Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com
Thank you for the guide. There was an issue with the private key of my merchIdentityCert and I fixed it. After installing the .cer file, expand it from the Keychain Access, and export 2 items as .p12 and convert it to .pem using OpenSSL. Now, I have a PEM file that contains both assets. Then I continued my process and didn’t get the below error in this time which I mentioned in the above post.

message: "apple pay ERROR", error: {}

But, After the request, I am getting below log,

message: "apple pay SUCCESS", resp: {"size":0,"timeout":0}

As well, In the Inspect Element → Network → (click on my request) → Preview

Top of the response Preview, It is displaying a message as “Reveal | This resource came from a local override”

Code Block
const merchIdentityCert = fs.readFileSync("./merchIdentityCert.pem")
const httpsAgent = new https.Agent({
cert: merchIdentityCert,
key: merchIdentityCert,
maxVersion: "TLSv1.2",
minVersion: "TLSv1.2"
})
const post = (url, body) => {
logger.info({ message: "apple pay START", url, body })
return fetch(url, {
body: JSON.stringify(body),
method: "POST",
agent: httpsAgent
}).then(resp => {
logger.info({ message: "apple pay SUCCESS", resp })
return resp
}).catch((error) => {
logger.info({ message: "apple pay ERROR", error })
return error
})
}

message: "apple pay SUCCESS", resp: {"size":0,"timeout":0} is not an expected response after requesting a session. But I am not getting an error also. Does anyone have an idea?

find my URL and request payload:
message: "apple pay START", url:
"https://-pay-gateway-cert.apple.com/paymentservices/startSession", body: {"merchantIdentifier":"***.*.****","displayName":"Test
Pay","initiative":"web","initiativeContext":"*-*-.**."}

What is the issue from my side?
I just want to confirm something:

As well, In the Inspect Element → Network → (click on my request) → Preview

The code you are displaying is running the payment session request from a server and not the client side, correct? It looks like it but I just wanted to be sure.

Regarding:

message: "apple pay SUCCESS", resp: {"size":0,"timeout":0}

Is this the response on the client? What is the corresponding response of the server? The server side request / response should give you the insight needed to debug this.


Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com
In Our architecture, Normally we are sending requests from the Client → FEBE → Server.

Here, FEBE is a node server and we are using it as a middle API to process requests and responses between Client and Server. 
We have deployed our Client app and FEBE(node server) in AWS servers on the same host. ( FEBE and Client are in the same docker)

When I am running the payment session request, It is going to FEBE(node server) from the Client and then hitting the apple pay servers to get the session object.

I'm sending the request from the FEBE and it will be triggered by the Client. My FEBE logs (server-side) are;

<My Server Logs>
Code Block
message: "apple pay START", url: "https://-pay-gateway-cert.apple.com/paymentservices/startSession",
body: {"merchantIdentifier":"***.*.****", "displayName":"Test Pay", "initiative":"web","initiativeContext":"*-*-.**."}

Code Block
message: "apple pay SUCCESS", resp: {"size":0,"timeout":0}

<My Code>
Code Block import fetch from "node-fetch"
import fetch from "node-fetch"
import fs from "fs"
import { Logger } from "../services/Logger"
import https from "https"
 
const logger = new Logger("Apple Pay Client")
 
const merchIdentityCert = fs.readFileSync("./merchIdentityCert.pem")
 
const httpsAgent = new https.Agent({
   cert: merchIdentityCert,
   key: merchIdentityCert,
   maxVersion: "TLSv1.2",
   minVersion: "TLSv1.2"
})
 
const post = (url, body) => {
   logger.info({ message: "apple pay START", url, body })
   return fetch(url, {
       body: JSON.stringify(body),
       method: "POST",
       agent: httpsAgent
   }).then(resp => {
       logger.info({ message: "apple pay SUCCESS", resp })
       return resp
   }).catch((error) => {
       logger.info({ message: "apple pay ERROR", error })
       return error
   })
}
 
/** Apple Pay */
export const performValidation = (url, body) => post(url, body)



message: "apple pay SUCCESS", resp: {"size":0,"timeout":0}

Okay, however these logs are being generated by your code. What about turning up the log level on your server and reviewing the what is happening there? If you see the response coming back from the Apple Pay servers and no errors are being thrown then that is a good indication that you have an issue in your actual code. If you see an error coming back, like an SSL error, then you also have an issue in your code and you need to look at the Merchant Identity Certificate again.


Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com
Hi All,

Able to resolve the {"size":0,"timeout":0} issue and it is related to node fetch library. I fixed it from my code level.

Apart from that, I used the below request to debug using the remote server, and It was giving the session object to me.

Code Block
curl -XPOST -H "Content-type: application/json" -d '{"merchantIdentifier":"merchant.***.xxxxx","displayName":"Test
Pay","initiative":"web","initiativeContext":"***-***-xxxxxx.xxxxxxxxxx.xx"}' --cert cert.pem:cert.pem
'https://apple-pay-gateway-cert.apple.com/paymentservices/startSession'


my code:


Code Block
import fetch from "node-fetch"
import fs from "fs"
import { promiseReject } from "../utils/misc"
import { Logger } from "../services/Logger"
import https from "https"
const logger = new Logger("Apple Pay Client")
const checkStatusAndGetJSON = (fetchResponse) =>
fetchResponse.ok
? fetchResponse.json()
: fetchResponse.json().then(promiseReject)
const merchIdentityCert = fs.readFileSync("./merchIdentityCert.pem")
const httpsAgent = new https.Agent({
cert: merchIdentityCert,
key: merchIdentityCert,
maxVersion: "TLSv1.2",
minVersion: "TLSv1.2"
})
const basicHeaders = {
"Accept": "application/json",
"lang": "en",
"Content-Type": "application/json"
}
const post = (url, body) => {
const start = Date.now()
return fetch(url, {
body: JSON.stringify(body),
headers: basicHeaders,
method: "POST",
agent: httpsAgent
}).then(resp => {
const duration = Date.now() - start
logger.debug(`apple pay call took ${duration} millis.`, { endpoint: url, method: "POST", duration })
return resp
}).then(checkStatusAndGetJSON)
}
/** Apple Pay */
export const performValidation = (url, body) => post(url, body)

I hope this will help someone. Thanks for the support!!!