GitHub Action to download and install Provisioning Profiles

August 6, 2026 · View on GitHub

License PRs welcome!

Getting Started

Use the same App Store Connect API key as upload-testflight-build and the same certificate secrets as import-codesign-certs.

Canonical GitHub ENVs

KindNamePurpose
VariableAPPSTORE_ISSUER_IDApp Store Connect issuer ID
VariableAPPSTORE_API_KEY_IDApp Store Connect API key ID
SecretAPPSTORE_API_PRIVATE_KEYContents of AuthKey_*.p8
SecretAPPSTORE_CERTIFICATES_FILE_BASE64Base64-encoded signing .p12
SecretAPPSTORE_CERTIFICATES_PASSWORDPassword for the .p12

Where to find the API credentials

Open App Store Connect → Users and Access → Integrations → App Store Connect API (Account Holder / Admin can create keys; Apple’s guide).

ValueHow to get it
APPSTORE_ISSUER_IDOn that page, copy Issuer ID (UUID at the top). Same for every team key.
APPSTORE_API_KEY_IDAfter you create a key, copy its Key ID. It also appears in the downloaded filename: AuthKey_<KEY_ID>.p8.
APPSTORE_API_PRIVATE_KEYDownload the .p8 when the key is created — Apple only shows it once. Store the file contents as the GitHub secret (cat AuthKey_<KEY_ID>.p8). Create the key with at least App Manager access.

Signing cert secrets (APPSTORE_CERTIFICATES_*) are produced by scripts/setup.sh / create-signing-certificate.sh, not the API keys page.

Local setup scripts take credentials as CLI args (--issuer-id, --api-key-id, --api-private-key-path). The APPSTORE_* names above are for GitHub Actions only. Scripts need curl, jq, openssl, and python3; configure-github.sh / setup.sh also need gh (gh auth login).

Profile names default to AppStore <bundle-id> and must match Xcode Release PROVISIONING_PROFILE_SPECIFIER and ExportOptions.plist. View profiles at Certificates, Identifiers & Profiles → Profiles.

Setup script examples

Shared credential flags used below:

--issuer-id 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' \
--api-key-id 'XXXXXXXXXX' \
--api-private-key-path ~/Downloads/AuthKey_XXXXXXXXXX.p8

Full bootstrap (new app)

Creates/reuses bundle ID, distribution cert + .p12, App Store profile, ExportOptions.plist, and GitHub vars/secrets:

./scripts/setup.sh \
  --bundle-id com.example.App \
  --name 'Example App' \
  --issuer-id 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' \
  --api-key-id 'XXXXXXXXXX' \
  --api-private-key-path ~/Downloads/AuthKey_XXXXXXXXXX.p8 \
  --p12-password 'choose-a-password' \
  --github-repo owner/name \
  --export-options ./ExportOptions.plist

App + app extension (one --name per --bundle-id, in order):

./scripts/setup.sh \
  --bundle-id com.example.App \
  --name 'Example App' \
  --bundle-id com.example.App.focus \
  --name 'Example App Focus' \
  --issuer-id 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' \
  --api-key-id 'XXXXXXXXXX' \
  --api-private-key-path ~/Downloads/AuthKey_XXXXXXXXXX.p8 \
  --p12-password 'choose-a-password' \
  --github-repo owner/name \
  --export-options ./ExportOptions.plist

Create / reuse provisioning profiles only

When the App ID and distribution certificate already exist in the Apple portal:

./scripts/create-provisioning-profile.sh \
  --bundle-id com.example.App \
  --profile-type IOS_APP_STORE \
  --issuer-id 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' \
  --api-key-id 'XXXXXXXXXX' \
  --api-private-key-path ~/Downloads/AuthKey_XXXXXXXXXX.p8

Optional: --name 'AppStore com.example.App', --certificate-id <id>, --recreate.

Create a signing certificate + .p12

Exactly one of --p12-password or --no-p12 is required:

./scripts/create-signing-certificate.sh \
  --issuer-id 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' \
  --api-key-id 'XXXXXXXXXX' \
  --api-private-key-path ~/Downloads/AuthKey_XXXXXXXXXX.p8 \
  --p12-password 'choose-a-password' \
  --output-dir ./signing
./scripts/create-signing-certificate.sh \
  --issuer-id 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' \
  --api-key-id 'XXXXXXXXXX' \
  --api-private-key-path ~/Downloads/AuthKey_XXXXXXXXXX.p8 \
  --no-p12 \
  --output-dir ./signing

Use --reuse to keep an existing ./signing cert instead of creating another.

Push credentials to GitHub

API vars/secret only (cert secrets already set):

./scripts/configure-github.sh \
  --github-repo owner/name \
  --issuer-id 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' \
  --api-key-id 'XXXXXXXXXX' \
  --api-private-key-path ~/Downloads/AuthKey_XXXXXXXXXX.p8

Including signing certificate secrets:

./scripts/configure-github.sh \
  --github-repo owner/name \
  --issuer-id 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' \
  --api-key-id 'XXXXXXXXXX' \
  --api-private-key-path ~/Downloads/AuthKey_XXXXXXXXXX.p8 \
  --p12-path ./signing/IOS_DISTRIBUTION.p12 \
  --p12-password 'choose-a-password'

Ensure bundle ID / write ExportOptions.plist

./scripts/ensure-bundle-id.sh \
  --bundle-id com.example.App \
  --name 'Example App' \
  --issuer-id 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' \
  --api-key-id 'XXXXXXXXXX' \
  --api-private-key-path ~/Downloads/AuthKey_XXXXXXXXXX.p8

./scripts/generate-export-options.sh \
  --bundle-id com.example.App \
  --bundle-id com.example.App.focus \
  --team-id TEAMID1234 \
  --output ./ExportOptions.plist

(ensure-bundle-id.sh prints the team / seed ID on the last line.)

Usage

- name: Download Provisioning Profiles
  uses: apple-actions/download-provisioning-profiles@v6
  with:
    bundle-id: 'com.example.App'
    profile-type: 'IOS_APP_STORE'
    issuer-id: ${{ vars.APPSTORE_ISSUER_ID }}
    api-key-id: ${{ vars.APPSTORE_API_KEY_ID }}
    api-private-key: ${{ secrets.APPSTORE_API_PRIVATE_KEY }}

Additional Arguments

See action.yml for more details.

Outputs

The action outputs an array of JSON objects to the action output named profiles. You can access and manipulate this data using workflow expressions.

Contributing

We welcome your interest in contributing to this project. Please read the Contribution Guidelines for more guidance.

License

Any contributions made under this project will be governed by the MIT License.