Migrate Fastlane to use Auth Keys

With the new requirement of having two factor authentication enabled on all apple id’s it is getting more frustrating to have CI upload apps to TestFlight as you have to manage a Fastlane/iTunes session.

This can be fixed by migration to use the new auth key provided by Appstore Connect. Fastlane already supports this so it is really easy to update any existing lanes to use the auth key.

I wrote another article on how to build and deploy your iOS app with GitHub Actions. This article uses the old method and now I want to show you how to migrate it.

Getting the Auth Key

First you need to head over to Appstore Connect and create a new auth key.

Generate a new auth key with minimum of App Manager access level
Copy the issuer id and key id and download the key

So now you have 3 pieces of information

  • The issuer ID
  • The Key ID
  • The key it self (a .p8 file)

Next step is to setup a json file that contains the information and then modify fastlane to use it.


Create a file called authkey.json and paste/modify the json below.

"key_id": "paste key id from appstore connect",
"issuer_id": "paste issuer id from appstore connect",
"key”: "paste in p8 contents here",
"duration": 1200,
"in_house": false

In the key part you must replace linebreaks with \n making it one line.


"key_id": "xxxXXxxXxx",
"issuer_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx",
"key”: "-----BEGIN PRIVATE KEY-----\nxxxxxxxxxxxxxxxxxx\nxxxxxxxxxxxxxxxxxx\nxxxxxxxxxxxxxxxxxx\n-----END PRIVATE KEY-----",
"duration": 1200,
"in_house": false

Modifying Fastlane

This is just a matter of adding the key path to the relevant commands.


match(type: "appstore", readonly: is_ci, api_key_path: "authkey.json")

Upload to TestFlight

upload_to_testflight(changelog: ENV["CHANGELOG"] || "No changelog provided", api_key_path: "authkey.json")

Full Example

This example is taken from my other article about fastlane and Github Actions.

platform :ios do
desc "Run tests"
lane :tests do
run_tests(scheme: "iOS")
desc "Push a new beta build to TestFlight"
lane :beta do
match(type: "appstore", readonly: is_ci, api_key_path: "authkey.json")
build_app(workspace: "Timeable.xcworkspace", scheme: "iOS")
upload_to_testflight(changelog: ENV["CHANGELOG"] || "No changelog provided", api_key_path: "authkey.json")
desc "Sets the version of the bundle to a RELEASE_VERSION passed in as an environment variable"
lane :set_release_version do
if version
UI.message("Setting version to #{version}")
increment_version_number(version_number: version)
increment_build_number(build_number: Time.now.to_i)
UI.user_error!("Environment variable RELEASE_VERSION not set")

Modifying Github Actions

We do not want to commit the raw authkey.json to git (I added the json file to my .gitignore so i wont commit it by mistake.), but rather an encrypted one. GitHub recommends that we use gpd.

$ gpg --symmetric --cipher-algo AES256 authkey.json

This gives you a new file called authkey.json.gpg.

Save the password and add it as a secret to your GitHub Actions.

Add an action secret called “APPSTORE_AUTHKEY” with the password you gave gpd when asked

Next up is to update GitHub Action to create the authkey.json file with the contents of the secret.


This scripts takes the APPSTORE_AUTHKEY variable with the password and decrypts the file into a plain text file that fastlane can read.

#!/bin/shgpg --quiet --batch --yes --decrypt --passphrase="$APPSTORE_AUTHKEY" --output authkey.json authkey.json.gpg

Remember to add chmod +x on decrypt_secret.sh to make it executable.


Update the GitHub workflow to decrypt the json file so fastlane can pick it up.

name: Deploy to Testflight on:
types: [created]jobs:
name: Deploy
runs-on: macos-latest

- name: Checkout
uses: actions/checkout@v2 - name: Select Xcode Version
uses: maxim-lobanov/setup-xcode@v1
xcode-version: latest-stable

- name: Install SSH key
uses: shimataro/ssh-key-action@v2
key: ${{ secrets.SSH_KEY }}
known_hosts: ${{ secrets.KNOWN_HOSTS }}

- name: Setup ruby
uses: ruby/setup-ruby@v1
ruby-version: 2.7.2
bundler-cache: true

- name: Install Pods
run: pod install

- name: Build & Distribute to Testflight
run: |
export LC_ALL=en_US.UTF-8
export LANG=en_US.UTF-8
bundle exec fastlane set_release_version
bundle exec fastlane beta
RELEASE_VERSION: ${{ github.event.release.tag_name }}
CHANGELOG: ${{ github.event.release.body }}

We basically just added one step, call decrypt_secret.sh. You can test it out locally by setting the APPSTORE_AUTHKEY environment variable.


Commit the updated workflow and test it out. GitHub Actions should now be able to test and deploy your iOS app.

This is a follow up article on how to build and deploy your iOS app with GitHub Actions.



Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store