What an App Store Connect API key actually is
Apple's App Store Connect API is a REST API that returns and modifies everything on
your App Store Connect account: apps, versions, builds, TestFlight testers, metadata,
screenshots, in-app purchases, sales reports, agreements. To authenticate to it, you
send a short-lived JSON Web Token (JWT) in an Authorization: Bearer
header. That JWT has to be signed with an ES256 private key that Apple knows about.
The API key is not a single secret. It is three pieces:
- Issuer ID — one per team, a UUID that identifies which App Store Connect team the request is for.
- Key ID — one per key, 10 characters (for example
2X9R4HXF34). - Private key (.p8) — the ES256 private key Apple gave you when you generated the key. This is the secret — treat it like a password.
The public half of the key stays with Apple. Every JWT you sign with the .p8 is cryptographically verified against that public half when Apple receives it.
Why API keys replaced Apple ID authentication
Before 2018, tools like iTMSTransporter and early Fastlane versions authenticated to Apple using an Apple ID and an application-specific password. That approach had three problems: it couldn't survive Apple's 2FA rollout without brittle session cookies, it tied a piece of automation to a single human's account, and revoking a compromised human account was disruptive. App Store Connect API keys fix all three: they're per-team credentials, not per-human; they do not interact with 2FA; and they can be revoked independently.
The old Apple ID flow still works for some tooling via the Transporter app, but every modern best practice — Apple's own documentation, Fastlane's current examples, Xcode Cloud, and tools like AppConsul — assumes API keys.
The three key roles: Admin, App Manager, Developer
When you generate a key, you choose a role. That role determines what the key can do. Apple currently exposes three roles for API keys:
| Role | Can do | Cannot do |
|---|---|---|
| Admin | Everything an Admin human can: manage apps, submit for review, manage team members, access financial reports, manage agreements. | Nothing Apple restricts to the Account Holder (legal contract acceptance, for example). |
| App Manager | Create apps, edit metadata, upload builds, manage TestFlight, submit for review, manage in-app purchases. | Manage team members, access banking or tax info, accept legal agreements. |
| Developer | Upload builds, manage TestFlight testers, read some app data. | Edit production metadata, submit apps for review, create apps. |
Rule of thumb: issue the lowest role the automation genuinely needs. A CI pipeline that only uploads builds and posts them to TestFlight can use Developer. A release automation that submits for review needs at least App Manager. Keep Admin keys for a small number of privileged automation surfaces — and never for interactive ad-hoc scripts.
Generating a key, step by step
You need to be an Account Holder or Admin on the team to generate API keys.
- Sign in at
appstoreconnect.apple.com. - Open Users and Access from the top-right menu, then select the Integrations tab. Alternatively, go directly to
appstoreconnect.apple.com/access/integrations/api. - If this is your first time, Apple will show a one-time legal terms acceptance screen. Read it (it governs API usage) and accept.
- Click the plus icon or Generate API Key button.
- Give the key a descriptive name. You will want to know later what each key is for. Examples:
AppConsul — Mac (Vaclav),GitHub Actions — release pipeline,Xcode Cloud. - Choose the Access role — Admin, App Manager, or Developer.
- Click Generate.
- On the next screen, click Download API Key. You will get a file named
AuthKey_XXXXXXXXXX.p8. This is the only time you can download it. - Copy the Key ID column value (it also appears in the .p8 filename) and the Issuer ID at the top of the page.
Store the .p8 somewhere that survives your laptop dying. macOS Keychain is fine for a personal developer machine (AppConsul stores its API keys there automatically). For CI, store it as an encrypted secret in your CI provider's secret manager (GitHub Actions Secrets, Bitrise Secrets, Xcode Cloud Environment Variables).
How the JWT is constructed (just enough to debug it)
If you use AppConsul, Fastlane, or Xcode Cloud, the JWT construction is handled for you. You just provide the issuer ID, key ID, and .p8. But when something fails with a 401, knowing what the JWT looks like saves hours.
Apple's App Store Connect JWT has three parts (header, payload, signature) joined by dots.
HEADER
{
"alg": "ES256",
"kid": "2X9R4HXF34",
"typ": "JWT"
}
PAYLOAD
{
"iss": "57246542-96fe-1a63-e053-0824d011072a",
"iat": 1714501234,
"exp": 1714502434,
"aud": "appstoreconnect-v1"
}
SIGNATURE: ES256(base64url(HEADER) + "." + base64url(PAYLOAD), .p8)
Things to watch:
expmust be no more than 20 minutes afteriat. Longer JWTs get rejected with 401.audmust be the literal stringappstoreconnect-v1.issis the issuer ID (your team), not the key ID.kidin the header is the key ID. Mixing upissandkidis one of the most common bugs.- The signature must be ES256 (ECDSA with P-256 + SHA-256). HS256 or RS256 won't work.
You then attach the JWT to every request:
GET https://api.appstoreconnect.apple.com/v1/apps
Authorization: Bearer eyJhbGciOiJFUzI1NiIs...
Using the key in real tooling
AppConsul
In AppConsul, open Settings → API Key and paste the issuer ID, key ID, and either the .p8 file path or the file contents. AppConsul stores the key in macOS Keychain — no file sits around in your home directory. The app then uses the key directly for every App Store Connect API request. Multiple keys are supported if you manage multiple teams.
Fastlane
Fastlane reads API keys via the api_key_path or inline hash. The
canonical form is a JSON file:
{
"key_id": "2X9R4HXF34",
"issuer_id": "57246542-96fe-1a63-e053-0824d011072a",
"key": "-----BEGIN PRIVATE KEY-----\nMIGTAg...\n-----END PRIVATE KEY-----",
"in_house": false
}
In your Fastfile:
app_store_connect_api_key(
key_id: ENV["ASC_KEY_ID"],
issuer_id: ENV["ASC_ISSUER_ID"],
key_content: ENV["ASC_KEY_CONTENT"],
is_key_content_base64: true
)
Xcode Cloud
Xcode Cloud uses its own ephemeral credentials internally for build uploads, but if you call the App Store Connect API from a custom ci_post_xcodebuild script you need to provide the issuer ID, key ID, and base64-encoded .p8 as environment variables (marked Secret).
GitHub Actions / Bitrise / CircleCI
Store the three values as separate secrets:
ASC_ISSUER_ID, ASC_KEY_ID, ASC_KEY_P8_BASE64.
In the workflow, decode the base64 back to a file before passing to Fastlane or your
own script. Never echo the secret values in logs.
Security best practices
- Never commit the .p8 file to git. Add
*.p8to your global.gitignore. If you accidentally committed one, treat it as compromised: revoke it, generate a new one, rewrite history only if the commit is not yet pushed. - Store secrets in macOS Keychain or your CI secret manager. Plain text in environment files (.env, .bashrc) is a common leak vector.
- Use separate keys for each consumer. CI, local development, AppConsul, Fastlane Match — each gets its own key. Then one leak revokes one key.
- Rotate on a schedule. Quarterly or semi-annually for high-value keys. Apple does not enforce rotation, but the blast radius of a forgotten leaked key grows with time.
- Use the lowest role that works. Don't issue Admin keys to a build-upload pipeline.
- Audit the integrations page regularly. Delete keys that belong to former team members or retired CI pipelines.
Revoking and rotating a key
When to rotate: immediately when a key leaks (a secret in a public commit, a laptop theft, a former employee with access), and periodically for high-value automation.
- Go to
appstoreconnect.apple.com/access/integrations/api. - Find the key in the list. Click the ellipsis or Revoke button at the end of the row.
- Confirm the revocation. Apple marks the key as revoked immediately — any JWT signed with it stops working on Apple's side within seconds.
- Generate a new key (same role as the revoked one, with a name that references the rotation, for example
GitHub Actions — release pipeline — 2026-04). - Download the new .p8 and update every consumer: CI secrets, AppConsul, local Fastlane configs.
- Run a test call with the new key before retiring the old setup completely.
If you don't know which places referenced the old key, a test call that logs a 401 is the fastest way to find stragglers.
Troubleshooting 401s and 403s
When a request to the App Store Connect API fails, the most common causes are:
- 401 Unauthorized — usually a JWT problem. Check: is
expwithin 20 minutes? Isaudexactlyappstoreconnect-v1? Is the signature ES256? Did you accidentally swap issuer ID and key ID? - 403 Forbidden — usually a role problem. The key is valid but the role lacks permission for the endpoint. Regenerate with a higher role or split the automation.
- 404 Not Found on a resource you know exists — usually a team mismatch. The key belongs to a different team than the app you're looking up.
- 429 Rate limit — back off. Apple's rate limits aren't publicly fixed but are generous for normal use.
Frequently asked questions
What is an App Store Connect API key?
A set of three values — issuer ID, key ID, and a .p8 private key — that authenticate scripts or tools to Apple's App Store Connect REST API via signed JWTs.
What are the three role types?
Admin (full), App Manager (apps and builds, no team management), Developer (limited, mainly builds and TestFlight).
Can I redownload the .p8?
No. Apple only lets you download it once, at generation time. Lose it and you revoke and regenerate.
Do keys expire?
The key itself does not have a fixed expiry. JWTs signed with it do: up to 20 minutes. Your tooling mints fresh JWTs as needed.
How do I revoke a compromised key?
From the Integrations page, click Revoke on the row. Revocation is immediate. Generate a replacement and update every consumer.
Can I share one key across the team?
Technically yes — keys are team-scoped, not user-scoped. But you should separate keys by consumer (CI, local, AppConsul) so revocation has minimal blast radius.
Skip the setup steps with AppConsul.
AppConsul walks through API key generation and validates the three values against Apple's servers before saving them to macOS Keychain. No more 401s from a typo in the issuer ID.
Get AppConsul →