Fastlane and App Store Connect API keys
Codemagic is the first CI/CD to make Apple M2 machines available to everyone (including the free tier!). This is a free upgrade from M1 machines with no price change.
I have recently had to set up a Continuous Integration/Continuous Development (CI/CD) pipeline for one of my side projects to upload an app to Testflight using Fastlane. I decided to use GitHub Actions as it is the CI provider I am most familiar with.
For a robust authentication and hassle free interaction with App Store Connect (ASC), Fastlane recommends that you use an App Store API Key. In fact, using an API key solves one of the most common CI issues people tend to have when communicating with App Store Connect: 2 factor authentication (2FA) requiring user input in an automated process.
I have created an App Store Connect API key and used it in Fastlane in the past but I recently found myself having to google a great part of this process again.
For this reason, I decided to put together an all you need to know guide on authentication with App Store Connect API keys in Fastlane. This article will also show you how to safely store the key we’ll create and make it available to GitHub Actions workflows.
Creating an App Store Connect API key
Follow these steps to create an App Store Connect API key:
- Go to App Store Connect and sign in.
- Go to the ‘Users & Access’ section.
- Select the Keys (1) menu and click the ’+’ button (2) to create a new key.
- Give it a name and a role and click the ‘Generate’ button. Make sure you give the key a role with just enough permissions for the tasks it is going to perform.
- The new key will now appear in the list. Click the ‘Download API Key’ button and hold on to it until the next section.
It is important to be aware that an API key can only be downloaded once.
- Copy the key id and your account’s issuer id. Fastlane needs to know both these values to validate the App Store Connect API key.
Storing the ASC API key
I find that the best place to store the new App Store Connect API key is in the CI provider’s secrets section.
While I’ll be using GitHub Actions in this article, the approach to save secrets will be very similar across most CI providers.
Creating an action secret
First, let’s see how we can create a secret and make it available to a GitHub Actions workflow:
- Open the ‘Settings’ page for your app’s repository on GitHub (1) and expand the ‘Secrets and Variables’ section from the menu on the left (2).
- Select the ‘Actions’ row from the expanded ‘Secrets and Variables’ section.
- Click on the ‘New Repository Secret’ button.
- You’ll be shown a page where you can create a secret and give it any name you want. The name you give it can later be used to retrieve the secret’s value from within a workflow as we’ll see in the following sections.
Storing the key
Fastlane provides multiple methods to authenticate with the App Store Connect API using an API key.
The way I prefer to use this key and pass it to Fastlane is as a string, as it enables me to store it as a secret on the CI and saves me from having to securely maintain a key file or duplicate across all different runners.
As the code below shows, the app_store_connect_api_key
built-in Fastlane action takes in three parameters: a key id, an issuer id and the contents of the key file itself:
app_store_connect_api_key(
key_id: 🤷♂️,
issuer_id: 🤷♂️,
key_content: 🤷♂️
)
As you will have guessed, we will need to create three GitHub Action secrets using the information we obtained when creating the App Store Connect API key:
- Key’s content:
- Name:
APP_STORE_CONNECT_API_KEY_CONTENT
. - Value: The content of the key file you downloaded from App Store Connect. To get the value for this secret, open the key file with a text editor and copy all of its contents to the clipboard.
- Name:
- Key’s identifier:
- Name:
APP_STORE_CONNECT_API_KEY_ID
. - Value: The id of the key that you copied earlier from App Store Connect.
- Name:
- Issuer identifier:
- Name:
APP_STORE_CONNECT_ISSUER_ID
. - Value: The issuer id for your App Store Connect account that you copied earlier.
- Name:
Once you have created these three secrets you can delete the API key file you downloaded from App Store Connect.
Retrieving the App Store Connect API key from Fastlane
Now that the secrets are available to GitHub Actions workflows, we need to make them accessible to the lane that needs to communicate with App Store Connect.
This is a two-step process:
- Make the secrets available as environment variables on the step that executes our lane in the GitHub Actions workflow.
- Retrieve these environment variables from the lane in the
Fastfile
.
Environment
Action secrets for a repository can be accessed from workflows with the ${{ Secrets.<SECRET_NAME> }}
syntax. The retrieved values can be made available to the step which needs them through its env
parameter:
name: Release to the app store
on:
push:
tags:
- 'v*.*.*'
jobs:
release:
runs-on: macos-12
steps:
- uses: actions/checkout@v3
- name: Upload to AppStore
run: bundle exec fastlane build_and_upload_to_appstore
env:
APP_STORE_CONNECT_API_KEY_CONTENT: ${{Secrets. APP_STORE_CONNECT_API_KEY_CONTENT}}
APP_STORE_CONNECT_ISSUER_ID: ${{Secrets. APP_STORE_CONNECT_ISSUER_ID}}
APP_STORE_CONNECT_API_KEY_ID: ${{Secrets. APP_STORE_CONNECT_API_KEY_ID}}
The names for the environment variables don’t need to match those of the secrets. For the sake of clarity, I decided to keep the naming consistent across the board.
The app_store_connect_api
action
Last but not least, the build_and_upload_to_appstore
lane needs to retrieve the environment variables we set in the previous section and tell Fastlane to use the App Store Connect API key we have created.
Fastlane has a way of retrieving environment variables through an object called ENV. ENV is a dictionary which holds all available environment variables as key-value pairs. This is how you can use it to retrieve the App Store Connect API secrets:
lane :build_and_upload_to_appstore do
asc_key_content = ENV["APP_STORE_CONNECT_API_KEY_CONTENT"]
asc_issuer_id = ENV["APP_STORE_CONNECT_ISSUER_ID"]
asc_key_id = ENV["APP_STORE_CONNECT_API_KEY_ID"]
end
Now that all secrets are available, we can pass them through to Fastlane’s app_store_connect_api_key built-in action, which will handle authentication for us:
lane :build_and_upload_to_appstore do
asc_key_content = ENV["APP_STORE_CONNECT_API_KEY_CONTENT"]
asc_issuer_id = ENV["APP_STORE_CONNECT_ISSUER_ID"]
asc_key_id = ENV["APP_STORE_CONNECT_API_KEY_ID"]
app_store_connect_api_key(
key_id: asc_key_id,
issuer_id: asc_issuer_id,
key_content: asc_key_content
)
end
When the app_store_connect_api_key action is executed, it sets a value in the lane shared context which makes the API key available to any other actions or lanes, such as deliver.
This means that you don’t need to hold on to the key yourself, Fastlane will do the heavy lifting for you.
If you wanted to hold on to the key, the app_store_connect_api_key action also returns it.
That’s it! You have safely and successfully set up authentication with an App Store Connect API key using Fastlane! 🎉