How to handle 2FA with Apple Developer accounts

Since February for all Apple Developer members it is required to be secured with two factor authentication (2FA). Previously this was only mandatory for the Account Holders. This makes it even harder now for teams to manage their developer accounts.
With most companies only having one account, you are limited to 2-3 distribution certificates.
This often means that the same certificate is shared across multiple teams and developers at the company.
The solution for most teams is to use one technical user to manage the certificates and provisioning profiles.
And as you can imagine technical users and 2FA (like SMS) don’t fit very well together.
App Store Connect API
You might expect that there is an official API to manage the apps, but until the last couple of years Apple didn’t provide one.
This meant, that CI/CD tools like fastlane were forced to get the session-cookie of html pages and use an unofficial API.
At WWDC18 Apple announced an official public API (App Store Connect API) to upload builds, create certificates and more. Unfortunately it took until October 2020 for the API to mature and to be integrated into fastlane. The advantage of using the Connect API is, that it does not require 2FA to execute, so it can easily be used in build pipelines and with all team members.
Setup with fastlane
1. Request access
The account holder needs to go to AppStore Connect (https://appstoreconnect.apple.com/access/api) and enable access for the API
2. Create key
Now login with the technical account and create a key
3. Integrate into the pipeline
There are two ways to integrate the key into fastlane depending on how you secure these secrets in the pipeline. You can put either key and ids into a json file:
D383SF739.json
1 2 3 4 5 6 7 |
{ "key_id": "D383SF739", "issuer_id": "6053b7fe-68a8-4acb-89be-165aa6465141", "key": "-----BEGIN PRIVATE KEY-----\nMIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHknlhdlYdLu\n-----END PRIVATE KEY-----", "duration": 1200, # optional "in_house": false, # optional but may be required if using match/sigh } |
Fastfile
1 2 3 |
lane :release do pilot( api_key_path: "fastlane/D383SF739.json" ) end |
Or put all values into the Fastfile:
Fastfile
1 2 3 4 5 6 7 8 9 |
ENV["APP_STORE_CONNECT_API_KEY_KEY_ID"] = "D383SF739" ENV["APP_STORE_CONNECT_API_KEY_ISSUER_ID"] = "6053b7fe-68a8-4acb-89be-165aa6465141" ENV["APP_STORE_CONNECT_API_KEY_KEY"] = "-----BEGIN PRIVATE KEY-----\nMIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHknlhdlYdLu\n-----END PRIVATE KEY-----" ENV["APP_STORE_CONNECT_API_KEY_IN_HOUSE"] = "false" lane :release do app_store_connect_api_key pilot end |
Conclusion
With that solution you would only need to authenticate with 2FA in some rare cases. For that we linked the account to a phone at the office.
There is currently one big caveat: The Connect API only works for AppStore- and not Enterprise-Accounts. Hopefully Apple adds support for these accounts too 🙂
Recent posts






Comment article