I am trying to integrate Apple Pay and as usual the apple documentation is amazing ...
I need to request an Apple Pay Payment Session
The request should be signed with a certificate I have in my Apple developer account
This is my current test file
import express from "express"
import fs from "fs"
import fetch from "node-fetch"
import https from "https"
const app = express()
app.get('/', function (req, res) {
const html = fs.readFileSync('index.html', 'utf8')
res.send(html)
})
app.get('/paymentSession', async function(){
const httpsAgent = new https.Agent({
rejectUnauthorized: false,
cert: fs.readFileSync('merchant_id.cer', 'utf8'),
});
const response = await fetch('https://apple-pay-gateway.apple.com/paymentservices/paymentSession',{
method: 'POST',
headers: {
'content-type': 'application/json'
},
agent: httpsAgent,
body: JSON.stringify({
merchantIdentifier: 'merchant.com.xxx.xxx',
displayName: 'xxx',
initiative: 'web',
initiativeContext: 'xxx.com'
})
})
console.log(response.status);
const text = await response.text()
console.log(text);
res.json({})
})
app.listen(3000)
I am trying with the certificate downloaded from my Apple developer account merchant_id.cer
, and I have the folowing error
node:internal/tls/secure-context:70
context.setCert(cert);
^
Error: error:0480006C:PEM routines::no start line
at node:internal/tls/secure-context:70:13
at Array.forEach (<anonymous>)
at setCerts (node:internal/tls/secure-context:68:3)
at configSecureContext (node:internal/tls/secure-context:157:5)
at Object.createSecureContext (node:_tls_common:116:3)
at Object.connect (node:_tls_wrap:1718:48)
at Agent.createConnection (node:https:169:22)
at Agent.createSocket (node:_http_agent:342:26)
at Agent.addRequest (node:_http_agent:289:10)
at new ClientRequest (node:_http_client:337:16) {
library: 'PEM routines',
reason: 'no start line',
code: 'ERR_OSSL_PEM_NO_START_LINE'
}
Then trying to convert merchant_id.cer
to merchant_id.pem
using openssl x509 -inform der -in merchant_id.cer -out merchant_id.pem
I have
file:///Users/ajouve/Developer/test/apple-pay/node_modules/node-fetch/src/index.js:108
reject(new FetchError(`request to ${request.url} failed, reason: ${error.message}`, 'system', error));
^
FetchError: request to https://apple-pay-gateway.apple.com/paymentservices/paymentSession failed, reason: 80E06BF801000000:error:0A00045C:SSL routines:ssl3_read_bytes:tlsv13 alert certificate required:ssl/record/rec_layer_s3.c:1586:SSL alert number 116
at ClientRequest.<anonymous> (file:///Users/ajouve/Developer/test/apple-pay/node_modules/node-fetch/src/index.js:108:11)
at ClientRequest.emit (node:events:526:35)
at TLSSocket.socketErrorListener (node:_http_client:495:9)
at TLSSocket.emit (node:events:514:28)
at TLSSocket._emitTLSError (node:_tls_wrap:994:10)
at TLSWrap.onerror (node:_tls_wrap:482:11) {
type: 'system',
errno: 'ERR_SSL_TLSV13_ALERT_CERTIFICATE_REQUIRED',
code: 'ERR_SSL_TLSV13_ALERT_CERTIFICATE_REQUIRED',
erroredSysCall: undefined
}
Seems that the certificate is not valid
Found the issue, I had to generate a csr
with private key and then use it
Generate the csr
openssl req -newkey rsa:2048 -keyout merchant_id.key -out merchant_id.csr
Convert the cer
to pem
openssl x509 -inform der -in merchant_id.cer -out merchant_id.pem
Configure the httpsAgent
const httpsAgent = new https.Agent({
rejectUnauthorized: false,
cert: fs.readFileSync('cert/merchant_id.pem', 'utf-8'),
key: fs.readFileSync('cert/merchant_id.key', 'utf-8'),
passphrase: 'xxx'
});