Connect Store Server API always return 401

We followed all the documentation, tried several combinations, but always returning 401. the below is being used in a nodejs application.

let options = {
        algorithm: 'ES256',
        header: {
            'alg': 'ES256',
            'typ': 'JWT',
            'kid': keyId
        }
    };
    let now = Math.round((new Date()).getTime() / 1000); // Notice the /1000 
    let nowPlus20 = now + 1199 // 1200 === 20 minutes;
    const claims = {
        "iss": issuerId,
        "exp": nowPlus20,
        "aud": "appstoreconnect-v1"
    };
    return jwt.sign(claims, key, options);

Please advise and provide some feedbacks, some solutions.

Hey @ir0nDev,

Thanks for posting on the developer forums!

Have you attempted to generate your JWT outside of your NodeJS application and make a GET request with a tool like Postman or from cURL on your local machine? If you are getting an authentication error, that is where I would start to verify that the token is being properly generated and that you can make a request without NodeJS which is acting as an abstraction layer right now for you to find out what is really going on.

The error message that you have posted above (body Unauthenticated) is from NodeJS and not the actual App Store Connect API body response so being able to see that will be valuable while troubleshooting.

Is it possible for you to share a link to the JWT Library (https://jwt.io/libraries) that you are using? Personally, when I need to generate tokens I do not need to include 'typ': 'JWT' in my header and I have no problems interacting with the App Store Connect API (If I include it my requests also work).

Thanks in advance for any additional information that you can share!

Hopefully this helps and happy coding!

Hello @ChuckMN,

Hope you are doing well. Thanks for your time. I will try to do what you mention and let you know.

In the mean time, I tried to use the "app-store-server-api" library that will handle everything from 0 to request. and tried with the below to generate tokens as well :

const jwt = require('jsonwebtoken'); 
const jws = require('jws');

let now = Math.floor((new Date()).getTime() / 1000); // Notice the /1000 
    let nowPlus20 = now + 600 // 1200 === 20 minutes

    let payload = {
        "iss": issuerId,
        "exp": nowPlus20,
        "aud": "appstoreconnect-v1",
        //bid: bundleId,
        iat: now,
        // "scope": [
        //     "GET /v1/users"
        // ],
        // nonce: '6edffe66-b482-11eb-8529-0242ac130003'// (0, uuid_1.v4)()
    }

    let signOptions = {
        "algorithm": "ES256", // you must use this algorythm, not jsonwebtoken's default
        header: {
            "alg": "ES256",
            "kid": keyId,
            "typ": "JWT"
        }
    }; 
    let token2 = jws.sign({header: signOptions.header, payload, secret: key.trim()});
    let token = jwt.sign(payload, key.trim(), signOptions);

Hello! I hope you are doing well. If you haven't already fixed the issue, I wanted to share with you that this worked for me.

const getAppFromAppleStoreConnect = async(callback)=>{

  const { homedir } = await import ('node:os');
  const privateKey =  fs.readFileSync(`${homedir()}/.appstoreconnect/private_keys/AuthKey_${process.env.APPLESTORE_KEY}.p8`, 'utf8');
  const issuerId = process.env.APPLEISSUEID;
  const now = moment().utc();

  const header = {
    "alg": "ES256",
    "kid": process.env.APPLESTORE_KEY, 
    "typ": "JWT" 
  }
  const payload = {
      "iss":issuerId,
      "iat": now.unix(),
      "exp": now.add(20, 'minutes').unix(),
      "aud": "appstoreconnect-v1",
  }
  
  const gen_jwt = jwt.sign(payload, privateKey, {
    algorithm: "ES256",
    header,
  });

  let dataToSend;
    async.series(
      [
        (cb) => {
          let options = {
            method: "GET",
            url: "https://api.appstoreconnect.apple.com/v1/apps",
            headers: {
              Authorization: `Bearer ${gen_jwt}`,
            },
            json:true
          };
          request(options, (err, response, body) => {
            if (err) {
              console.log(err);
              cb(err);
            } else {
              dataToSend = body;  
              cb();
            }
          });
        },
      ],
      (err) => {
        if (err) callback(err);
        else {
          callback(null, dataToSend);
        }
      }
      );
    };
Connect Store Server API always return 401
 
 
Q