I'm validating subcription from an Apple's IAP Receipt using app-store-server-library-node. Everything is fine during dev in Apple's "Sandbox" mode.
Once I upload my app and run it from a testFlight build I've go this error:
Error: error:0480006C:PEM routines::no start line at new X509Certificate (node:internal/crypto/x509:119:21) at /opt/app/node_modules/@apple/app-store-server-library/jws_verification.ts:55:65 at Array.map () at new SignedDataVerifier (/opt/app/node_modules/@apple/app-store-server-library/jws_verification.ts:55:53)
Here is how I initiate the call :
(keys and ids have been changed for obvious security reason)
const issuerId = '6f1337a3-1234-4929-9ccd-774e8c02fa18';
const keyId = 'FG7N3NY68Y';
const bundleId = 'com.appname.app';
const teamId = '6JZPD4JMSJ';
// appAppleId is required when the environment is Production
const appAppleId = teamId+"."+bundleId;
const appleEnv = Environment.PRODUCTION;
const filePath = path.join(ROOT_FOLDER, `/keys/AppleApi_AuthKey_${keyId}.p8`);
const privateKey = fs.readFileSync(filePath, 'utf8');
const client = new AppStoreServerAPIClient(privateKey, keyId, issuerId, bundleId, appleEnv);
const appleRootCAs = [
fs.readFileSync(path.join(ROOT_FOLDER, '/keys/AppleRootCer/AppleIncRootCertificate.cer')),
fs.readFileSync(path.join(ROOT_FOLDER, '/keys/AppleRootCer/AppleComputerRootCertificate.cer')),
fs.readFileSync(path.join(ROOT_FOLDER, '/keys/AppleRootCer/AppleRootCA-G2.cer')),
fs.readFileSync(path.join(ROOT_FOLDER, '/keys/AppleRootCer/AppleRootCA-G3.cer')),
];
const enableOnlineChecks = true;
console.log('privateKey = ', privateKey);
const verifier = new SignedDataVerifier(appleRootCAs, enableOnlineChecks, appleEnv, bundleId, appAppleId);
I'm first trying to run in Production env then in sandbox as requested in apple's documentation. The files are correctly read. Login private key shows:
privateKey = -----BEGIN PRIVATE KEY----- MIGTAbEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQg4n35kqKOEJA5ITBZ lf5QfWlaj1re4R60jFflAmzfJQKgCgYIKoZIzj0DABehRANCAATvNxWUh/WGfw+q OW1kMsTRNyBN7IwS861VjFvtQKN7r8wlvG1jTw+vTpsv/84xZw/H+IDmFLnOkAbS yRfk1PcT -----END PRIVATE KEY-----
more log values :
enableOnlineChecks : true
environment : Production
bundleId : com.appname.app
appAppleId : 6JZPD4JMSJ.com.appname.app <= is this appId format correct ?
(All keys and appname/ team id have been change for obvious security reason)
Can you see anything I do wrong ?
Should we "enableOnlineChecks" ?
Thank you for your help.
The "PEM routines::no start line" error is referenced a lot on the web when trying to decode a .PEM file certificate with format :
-----BEGIN PRIVATE KEY----- MIGTAbEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQg4n35kqKOEJA5ITBZ lf5QfWlaj1re4R60jFflAmzfJQKgCgYIKoZIzj0DABehRANCAATvNxWUh/WGfw+q OW1kMsTRNyBN7IwS861VjFvtQKN7r8wlvG1jTw+vTpsv/84xZw/H+IDmFLnOkAbS yRfk1PcT -----END PRIVATE KEY-----
I've fix the issue by replacing Apple's root certificate binary files ( .cer ) with .pem files.
Change the file format of each root certificate file using:
openssl x509 -inform der -in AppleRootCA-G3.cer -out AppleRootCA-G3.pem
Then reference them in the code using
const appleRootCAs = [
fs.readFileSync(path.join(ROOT_FOLDER, '/keys/AppleRootCer/AppleIncRootCertificate.pem'), 'utf-8'),
fs.readFileSync(path.join(ROOT_FOLDER, '/keys/AppleRootCer/AppleComputerRootCertificate.pem'), 'utf-8'),
fs.readFileSync(path.join(ROOT_FOLDER, '/keys/AppleRootCer/AppleRootCA-G2.pem'), 'utf-8'),
fs.readFileSync(path.join(ROOT_FOLDER, '/keys/AppleRootCer/AppleRootCA-G3.pem'), 'utf-8'),
];
Don't forget the second parameter on each line: " 'utf-8')," as we are now decoding a string from the .pem file.
This is solving the issue.