Skip to content
Latchkey

altool "Unable to authenticate" with App Store Connect API key in CI

xcrun altool reached App Store Connect but could not authenticate with the API key you passed. The key id and issuer id must match a key that exists, and the AuthKey_<keyid>.p8 must be readable, otherwise the upload is rejected before the binary is sent.

What this error means

altool --upload-app or --validate-app fails with "Unable to authenticate. Invalid value provided for the API key id" or "Could not find the private key file AuthKey_XXXX.p8". Password-based logins are not affected; only the API key path fails.

altool
Error: Unable to authenticate. Invalid value provided for the API key id 'ABCD1234'.
You can find your API key id in the App Store Connect Users and Access settings.

Common causes

Key id or issuer id does not match a real key

The --apiKey value or --apiIssuer UUID is wrong, was revoked, or belongs to a different team than the bundle you upload. App Store Connect rejects the pair.

The .p8 private key file is not found

altool looks for AuthKey_<keyid>.p8 in ./private_keys, ~/private_keys, ~/.private_keys, or ~/.appstoreconnect/private_keys. If the secret was written elsewhere, altool cannot load it.

How to fix it

Place the .p8 where altool searches and pass the right ids

  1. Write the API key secret to one of altool's search directories as AuthKey_<keyid>.p8.
  2. Copy the Key ID and Issuer ID from App Store Connect, Users and Access, Integrations.
  3. Pass both ids on the altool command and re-run the upload.
Terminal
mkdir -p ./private_keys
echo "$ASC_KEY_P8" > ./private_keys/AuthKey_$ASC_KEY_ID.p8
xcrun altool --upload-app -f App.ipa -t ios \
  --apiKey "$ASC_KEY_ID" --apiIssuer "$ASC_ISSUER_ID"

Confirm the key is active and scoped

In App Store Connect, Users and Access, Integrations, App Store Connect API, verify the key is not revoked and has at least the App Manager role. A revoked or under-scoped key authenticates as invalid.

How to prevent it

  • Store the .p8, key id, and issuer id as CI secrets and never commit them.
  • Write the .p8 to ./private_keys at job start so altool finds it deterministically.
  • Rotate the key in one place and update the secret, not the workflow.

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →