Apple Secrets and where to find them

Notarization of Mac Apps

20. July 2026 allgemeines

In the depths of Mac Developer pages and Store Pages, there are various IDs, certificates, and passwords that occasionally need to be set and found. They are sometimes needed when 'notarizing' apps.

App in first version ready - nice! Now it's time for the release. To allow others to open and use the app without issues or warning messages, there are several steps to follow:

  1. Production build of the app

  2. Notarization

  3. Hosting the `.dmg` files or submitting to the App Store

Before we look at the individual secrets, it's worth taking a look at why they are needed at all – because without understanding signing and notarization, the IDs are just a collection of cryptic character strings.

Why all this? Gatekeeper, Signing and Notarization

Since macOS Catalina, Gatekeeper checks every app that has been downloaded from the internet before it starts for the first time. If someone downloads a .dmg from your website and the app is not properly signed and notarized, they will (in the best case) see the message "… can't be opened, as Apple could not verify it for malicious software" – in the worst case, the app can't even be opened at all. For an app you want to distribute, this is a K.-o.-Kriterium.

Three terms must be distinguished:

1. Code Signing (Signing)

When signing, the app is cryptographically signed with your Developer-ID certificate. This serves two purposes:

  • Identity – macOS can prove that the app really comes from you (your Apple Developer team).

  • Integrity – any subsequent changes to the app break the signature, macOS recognizes manipulations.

Signing is done with the command-line tool codesign. Important: The app must be signed with Hardened Runtime (codesign --options runtime) for later notarization. This is a series of runtime security measures (no code injection, no unsigned libraries, etc.), which Apple requires.

2. Notarization (Notarization)

Signing alone is not enough for Gatekeeper. The app must also be notarized. To do this, you upload the signed app to Apple's Notary Service. Apple automatically checks it (no human, no content review like in the App Store!) for:

  • valid signature with a Developer-ID certificate,

  • activated Hardened Runtime,

  • known malicious software.

If the check passes, Apple issues a Notarization ticket. From this point on, Gatekeeper trusts the app. Notarization thus does not mean that your app is good or functional – only that it is cleanly signed and free of known malware.

The modern tool for this is notarytool (the older altool is deprecated).

3. Stapling (Attaching the ticket)

After successful notarization, the ticket is on Apple's servers. To allow Gatekeeper to check it offline – for example, when the user has no internet connection on first launch – the ticket is "stapled" directly to the .app or .dmg with xcrun stapler staple. Without stapling, Gatekeeper requests the ticket online from Apple on first launch; with stapling, the app is completely autonomous.

The ingredients: Which IDs, certificates, and keys do you need?

For the path "Developer ID + Notarization" (distribution outside the App Store, e.g. as .dmg from your own website), you need six things:

What

Purpose

Where to find

Team ID

identifies your Developer team

developer.apple.com → Membership

Developer ID Application certificate (.p12)

signs app & DMG

Keychain Access (Export from "My Certificates")

Certificate password

protects the .p12 file

you set it yourself during export

App Store Connect API Key ID

Auth for notarytool

App Store Connect → Integrations

Issuer ID

Auth for notarytool

App Store Connect → Integrations

API Private Key (.p8)

Auth for notarytool

App Store Connect → one-time download

The prerequisite for all of this is a paid membership in the Apple Developer Program (99 $\/year).

Team ID

The Team ID is a ten-character identifier of your Developer team (e.g. AB12CD34EF).

Location

developer.apple.com/account → Membership details → there you'll find the Team ID.

It also appears in parentheses after the name of your signature certificate (Developer ID Application: Your Company (AB12CD34EF)).

Developer ID Application certificate (.p12) + password

This is the decisive certificate for distribution outside the App Store. Caution: There are multiple certificate types – for our purpose, "Developer ID Application" is explicitly required (not "Apple Development", not "Apple Distribution").

Create (if not already present):

  • Conveniently via Xcode: Xcode → Settings → Accounts → select Team → Manage Certificates → + → Developer ID Application. The certificate lands directly in your login Keychain.

  • Alternatively manually via developer.apple.com → Certificates: create a CSR (Certificate Signing Request) via Keychain Access → Certificate Assistant → request a certificate from a certificate authority, upload it, download the .cer file and install it by double-clicking.

Export as .p12:

  1. Open Keychain Access → category My Certificates.

  2. Find the entry Developer ID Application: Your Company (TEAMID) and open the disclosure triangle – underneath there must be a private key. Without this private key, the export is worthless because you can't sign.

  3. Right-click → Export → Format .p12 → set a password.

This password is the Certificate password (in the CI below APPLE_CERTIFICATE_PASSWORD).

Since GitHub Actions & Co. only store text secrets, and the .p12 is binary, you encode it in Base64:

 1base64 -i DeveloperID.p12 | pbcopy

The resulting text is the actual certificate secret (APPLE_CERTIFICATE); in the CI it is converted back with base64 --decode before import.

App Store Connect API Key (Key ID, Issuer ID, .p8)

signature tool notarytool must authenticate with Apple. The modern, CI-friendly way is an App Store Connect API Key (the alternative – Apple ID + app-specific password – see below).

Location & Creation: App Store Connect → Users and Access → Integrations tab → App Store Connect API → Team Keys → Generate API Key. A role of Developer is sufficient for notarization.

After creating, you get three things:

  • Key ID – the identifier of the new key (APP_STORE_CONNECT_KEY_ID).

  • Issuer ID – stands above the key list, applies to all keys in the team (APP_STORE_CONNECT_ISSUER_ID).

  • AuthKey_.p8 – the private key file. Only downloadable once! If you lose it, you must generate a new key. Its entire content (including the -----BEGIN PRIVATE KEY------ lines) is the secret APP_STORE_CONNECT_PRIVATE_KEY.

 1pbcopy < AuthKey_XXXXXXXXXX.p8

The process for notarization

How the parts fit together – in principle the exact steps that the CI pipeline automates:

# 1. Signing – with Hardened Runtime and secure timestamp

 1codesign --force --options runtime --timestamp \
 2  --sign "Developer ID Application: Your Company (TEAMID)" YourApp.app

# 2. Package for upload (zip the app, or directly use the DMG)

 1ditto -c -k --keepParent YourApp.app app.zip

# 3. Submit to the Notary Service and wait for the result

 1xcrun notarytool submit app.zip \
 2  --key AuthKey_XXXXXXXXXX.p8 \
 3  --key-id "$APP_STORE_CONNECT_KEY_ID" \
 4  --issuer "$APP_STORE_CONNECT_ISSUER_ID" \
 5  --wait

# 4. Staple the ticket so Gatekeeper can check it offline

 1xcrun stapler staple YourApp.app

# 5. Verify

 1spctl -a -vvv YourApp.app     # should say "accepted / Notarized Developer ID"

When notarizing a .dmg, you repeat signing, notarization, and stapling for the DMG itself – both the disk image and the contained app are clean.

Into CI: store the secrets in GitHub Actions

In a GitHub Actions workflow, store the six values as Repository Secrets (Settings → Secrets and variables → Actions) and then pass them as environment variables to the signing/notarization steps. Conveniently, you can also use the CLI – gh secret set NAME (without a value) asks for the value interactively and stores it so it doesn't appear in the shell history:

 1gh secret set APPLE_TEAM_ID
 2gh secret set APPLE_CERTIFICATE_PASSWORD
 3gh secret set APP_STORE_CONNECT_KEY_ID
 4gh secret set APP_STORE_CONNECT_ISSUER_ID
 5gh secret set APPLE_CERTIFICATE  < < (base64 -i DeveloperID.p12)
 6gh secret set APP_STORE_CONNECT_PRIVATE_KEY < AuthKey_XXXXXXXXXX.p8

Signing vs. Notarization vs. App Store – when to use what?

The terms are often confused. There are two fundamentally different distribution paths, and they require different certificates:

  • Developer ID + Notarization (this article): You distribute the app yourself as .dmg/.app – via your website, a download link, an internal server. Certificate: Developer ID Application. You notarize it yourself. Gatekeeper opens the app without a warning.

  • App Store: The app goes through App Store Connect for review and is distributed via the Store. Certificate: Apple Distribution / App Store. A separate notarization is not needed – the App Store process does it. This also adds content review by Apple.

For a tool you want to hand out to colleagues or customers as a simple download, the Developer ID path is usually the right choice.

Common pitfalls

  • .p12 exported without private key. Only with the private key can you sign. Before exporting, check the disclosure triangle in the Keychain.

  • .p8 lost. The API Private Key is only downloadable once. If it's lost, you need a new key.

  • Certificate name doesn't match the signature string. The signature identity must match the certificate's Common Name exactly. Check with security find-identity -v -p codesigning.

  • Forgot Hardened Runtime. Without --options runtime (and --timestamp), the Notary Service rejects the app.

  • Only the app notarized (or vice versa). Sign, notarize, and staple both levels.

  • Wrong certificate type. "Apple Development" is for development, not distribution – for notarization, "Developer ID Application" is required.

Appendix: the version without API Key

Instead of the App Store Connect API Key, notarytool can also authenticate with Apple ID + app-specific password + Team ID:

 1xcrun notarytool submit app.zip \
 2  --apple-id "you@example.com" \
 3  --password "abcd-efgh-ijkl-mnop" \
 4  --team-id "TEAMID" --wait

You create the app-specific password under account.apple.com → Sign In & Security → App-specific passwords. For automated pipelines, the API Key is the cleaner choice: no personal account involved, revocable granularly, and no dependency on two-factor authentication for an Apple ID.

Curious?

Feel like cooking this up together?

Whether it's an idea, a refactor, or a new build — tell us briefly about your project. We'll get back to you within 24 hours.