App Store Connect API key (.p8): create and use it
By Mehdi Azizi
Published , 10 min
The App Store Connect API key (.p8) downloads only once. Role, Issuer ID, Key ID, revoking, and using it with Expo, fastlane or a script.
An App Store Connect API key lets a tool, like EAS, fastlane, RevenueCat or your own script, act on your account without your password or two-factor authentication. Apple keeps the public half of the key, and you download the private half, a .p8 file, only once. With that file, the Issuer ID and the Key ID, you sign tokens valid for 20 minutes at most for most requests.
I publish my iOS apps, including TradaZen and Nolera, with Expo. One team key with the App Manager role serves RevenueCat, my Expo builds and a command-line tool that edits my listings. This guide follows the Apple, Expo and fastlane pages I reread on November 3, 2026. Don't confuse it with the service keys slipped into an app's code: those are covered in secret API key in an Expo app.
What an App Store Connect API key does
According to Apple's documentation, the App Store Connect API requires a JWT for every request. You generate it and sign it with your private key. The key only works for this API: you can't use it for other Apple services.
Its value fits in one sentence: nobody has to approve the sign-in. Your Apple ID runs into two-factor authentication, which blocks any automation. The EAS Submit iOS guide shows what this changes for submitting an Expo app.
First: request API access
You can't create your first key right away. App Store Connect Help is clear: the Account Holder must first request access to the API. They open Users and Access, click Integrations, then Request Access. Apple reviews each request case by case.
The Account Holder is the person who enrolled the account. If you're just starting, that's you: the Apple developer account guide walks through enrollment.
Team key or individual key
Apple offers two types of keys. Here are their differences, taken from the documentation and App Store Connect Help:
| Criterion | Team key | Individual key |
|---|---|---|
| Who can generate it | Account Holder or Admin | Almost any user |
| Accessible apps | All of them, no exceptions | The user's apps |
| Permissions | The chosen role | The user's permissions |
| Number of keys | Several | One active per person |
| Certificates and profiles | Yes, depending on role | No |
| Sales, finance, notaryTool | Depending on role | No |
| Token field | iss = Issuer ID | sub = user |
"Almost any user" means, according to Apple: Account Holder, Admin, App Manager, Customer Support, Developer and Marketing, unless an Admin or the Account Holder has removed their permission to generate an individual key.
For Expo or fastlane, pick a team key. An individual key has no access to the provisioning endpoints, the ones that create certificates and profiles. fastlane's documentation confirms it: team keys are required for any provisioning-related access.
Which role to give your key
A team key accesses every app on the account, whatever its role. The role decides what it can do. Apple warns that an Admin key can create and delete users: give the smallest role that covers your use. The permissions below come from Apple's roles table.
| Key usage | Roles that allow it |
|---|---|
| Upload builds | Admin, App Manager, Developer |
| Manage TestFlight builds | Admin, App Manager |
| Create certificates and profiles | Admin, App Manager |
| Submit an app for review | Admin, App Manager |
| Import products and prices (RevenueCat) | App Manager at minimum |
| Generate other team keys | Admin |
The RevenueCat row comes from its documentation. Expo's guide, on the other hand, gives the key the Admin role. On my apps, App Manager is enough: EAS creates distribution profiles with it, and RevenueCat imports the products.
Once the key is generated, you can't change its name or its role. To change them, you have to revoke it and generate another one.
Create a team key, step by step
You need an Admin or Account Holder account. According to Apple:
- Open Users and Access, then the Integrations tab.
- Pick App Store Connect API in the left column, then the Team Keys tab.
- Click Generate API Key, or the + button.
- Name the key. The name is just for you, it isn't part of the key. Name it after the tool that will use it.
- Pick the role under Access, then click Generate.
- Download the private key with the Download API Key link.
The download link disappears as soon as you've downloaded the file, and Apple keeps no copy. Store the
.p8before closing the page.
Then write down the two identifiers. According to Apple's page on tokens, the Issuer ID shows at the top of the Integrations page, with a Copy button. The Key ID appears in the list of active keys: hover over it to reveal Copy Key ID. The Issuer ID is the same for all team keys on the account. The Key ID is unique to each key.
For an individual key, it's shorter: open your user profile, scroll down to Individual API Key and click Generate API Key. Here too, the download only happens once.
Store the .p8 file
Apple asks you to treat the key like a password: don't share it, don't store it in a code repository, never embed it in an app's code. My routine:
- A folder outside the project, or your CI tool's secrets manager.
- The keys folder in your
.gitignore, if the file has to live in the project during an upload. - Strict permissions. A command-line tool for App Store Connect refused my
.p8as long as the file was readable by other accounts. Achmod 600fixed it. - One key per tool. Apple lets you generate several keys, with whatever roles you want.
I didn't follow that last point at first. My App Manager key serves RevenueCat, my builds and my listing tool all at once. If I have to revoke it, three tools go down together. If I did it again, I'd create one key per tool, so I could cut one off without touching the others.
Use it with Expo
Three ways to give the key to EAS:
- Let EAS manage it.
eas credentials --platform ioscan create a key and keep it on Expo's servers. It's the simplest path. - Declare it in
eas.json. Thesubmitprofile acceptsascApiKeyPath,ascApiKeyIssuerIdandascApiKeyId. According to the eas.json reference, these fields accept environment variables, like$ASC_API_KEY_PATH. - Pass it through the environment. The EAS CLI repo documents
EXPO_ASC_API_KEY_PATH,EXPO_ASC_KEY_IDandEXPO_ASC_ISSUER_ID. For an individual key, you leave out the Issuer ID.
One limit to know for builds: Expo points out that the official API can't link an App Group, a Merchant ID or a CloudKit container. You then need to sign in with your Apple ID, locally. I ran into this on Nolera with its widget's app group: the key enabled the capability without linking the group. I did that linking in Apple's developer portal. If capability syncing gets stuck, EXPO_NO_CAPABILITY_SYNC=1 turns it off, and you enable the capability yourself on the app ID. Build signing is covered in iOS certificate and provisioning profile.
Use it with fastlane
fastlane reads the key from a JSON file. The key_id, issuer_id and key fields, the latter being the contents of the .p8, are required. duration and in_house are optional. Dummy values:
{
"key_id": "XXXXXXXXXX",
"issuer_id": "your-issuer-id",
"key": "-----BEGIN PRIVATE KEY-----\nMIGT...\n-----END PRIVATE KEY-----",
"duration": 1200,
"in_house": false
}
You then pass this file to an action, for example fastlane pilot distribute --api_key_path fastlane/cle.json. In a Fastfile, the app_store_connect_api_key action takes key_id, issuer_id and key_filepath. The session duration can't exceed 1,200 seconds, or 20 minutes. Not every action supports it: fastlane notes for example that produce and pem don't work with an API key.
Use it in your own script
Without a tool, you build the token yourself. Apple sets the recipe:
- Header:
algisES256,kidis your Key ID,typisJWT. - Payload, team key:
iss, your Issuer ID;iat, the creation time;exp, the expiration time;aud, which isappstoreconnect-v1. - Payload, individual key:
subisuserinstead ofiss. - Lifetime: beyond 20 minutes, Apple rejects the token for most requests.
In Python, with the PyJWT library and its crypto dependency, installed with pip install pyjwt[crypto] according to its documentation. In the Mac terminal, add quotes: pip install "pyjwt[crypto]", otherwise zsh rejects the brackets.
import time
import jwt
KEY_ID = "XXXXXXXXXX"
ISSUER_ID = "your-issuer-id"
with open("AuthKey_XXXXXXXXXX.p8") as f:
private_key = f.read()
now = int(time.time())
token = jwt.encode(
{"iss": ISSUER_ID, "iat": now, "exp": now + 20 * 60, "aud": "appstoreconnect-v1"},
private_key,
algorithm="ES256",
headers={"kid": KEY_ID, "typ": "JWT"},
)
print(token)
Then you send it in the Authorization header, as in Apple's example:
curl -H "Authorization: Bearer $TOKEN" "https://api.appstoreconnect.apple.com/v1/apps"
I ran this script on November 3, 2026 with a throwaway key generated on my machine: the token's header and payload match Apple's page, and the ES256 signature verifies. I didn't send it to Apple's API with this test key, which doesn't exist on Apple's side. Reuse the same token while it's still valid: Apple recommends it for better performance.
Revoke a key
Revoke a key as soon as it's lost, compromised, or no tool uses it anymore. According to App Store Connect Help, with an Account Holder or Admin account:
- Open Users and Access, then Integrations.
- Pick Team Keys, or Individual Keys, then click Edit.
- Check the keys to revoke, then Revoke Key.
- Confirm with Revoke.
A revoked key can never be reactivated. Apple shows it for 30 days under Revoked. Every tool that used it then fails to authenticate. With Expo, the message is "App Store Connect rejected the API authentication credentials". This message and other upload failures are explained in EAS upload errors and how to fix them. If the key isn't compromised, set up the new one before cutting off the old one. If it is, Apple asks you to revoke it immediately.
For your own individual key: your profile, Individual API Key, then Revoke.
My .p8 key checklist
- The Account Holder has requested API access.
- The key is a team key if it's used for builds or profiles.
- Its role is the smallest that covers the use, and its name says which tool uses it.
- The
.p8is stored outside the repo, with strict permissions and an encrypted backup. - The Issuer ID and Key ID are written down separately, without the file.
- Each tool has its own key, so you can revoke just one.
Automate your release without leaving your key behind
The key is just one piece of the journey. The iOS & Android Kit starts from the starter code of my apps, subscriptions included, and walks through four steps to the App Store, at your own pace. If you're hooking up RevenueCat with this key, the full setup is in RevenueCat and iOS in-app subscriptions.
If you're preparing your first release, take your free diagnostic: it tells you what's really blocking you and sends you my checklist to avoid Apple rejections. The publish an app on the App Store page covers every step, from the listing to approval.
Frequently asked questions
How do you create an App Store Connect API key?
The Account Holder first requests API access. Then an Admin opens Users and Access, Integrations tab, App Store Connect API, Team Keys. They click Generate API Key, pick a name and a role, generate the key, then download the .p8 file.
Can you re-download a lost .p8 key?
No. The file downloads only once, and Apple keeps no copy. Revoke the lost key, then generate a new one and update every tool that used it.
Where do you find the Issuer ID and the Key ID?
In App Store Connect, Users and Access menu, Integrations tab. The Issuer ID shows at the top of the page. The Key ID is in the list of active keys. An individual key doesn't use an Issuer ID.
Which role should you give a key used by Expo?
Expo's guide gives it the Admin role. According to Apple's roles table, App Manager is enough to upload builds and create certificates and profiles. That's the role of my key, used for my Expo builds.
Can you change an API key's role?
No. Apple doesn't let you change a key's name or role after it's created. Revoke it, then generate a new one with the right role.
Does an App Store Connect API key expire?
Apple's pages don't mention any expiration for the key, only revocation. It's the tokens signed with it that expire, after 20 minutes at most for most requests.

