Making macOS .app Bundles Signing & Notarizing

This guide walks you through signing, notarizing, and distributing macOS .app bundles so your apps launch securely and without errors on any Mac.

Making macOS .app Bundles work on other people's machines: Signing & Notarizing

I figured out how to bundle some source code into a GUI binary (fyne in my case).
Then I ran into a problem: it's either forbidden to execute or marked as "damaged" when other people use it.
You'll have to do the following so that it just werks.

tl;dr

Hint: this works only if the Apple setup is already done, in which case you probably have a similar snippet somewhere.

sign-notarize: build-gui
 codesign --force --deep --timestamp --options runtime --sign "$(CERT_NAME)" "$(BUILD_DIR)/$(DOTAPP)"
 zip -r "$(BUILD_DIR)/$(DOTAPP).zip" "$(BUILD_DIR)/$(DOTAPP)"
 xcrun notarytool submit "$(BUILD_DIR)/$(DOTAPP).zip" --keychain-profile "notarytool-profile" --wait
 xcrun stapler staple "$(BUILD_DIR)/$(DOTAPP)"
 rm "$(BUILD_DIR)/$(DOTAPP).zip"
 zip -r "$(BUILD_DIR)/$(DOTAPP)-signed.zip" "$(BUILD_DIR)/$(DOTAPP)"

The Process

You'll need to perform a handful of steps: build → sign → zip → notarize → staple → re-zip → distribute.

Prerequisite: Apple Developer Certificate

If you're asking "what certificate?", you won’t like this part.
You need a $99/year Apple Developer account. No way around it.

  1. Sign up at developer.apple.com
  2. Create certificates in Keychain Access:
    • Keychain Access → Certificate Assistant → Request from Certificate Authority
    • Save request file, upload to Apple Developer portal
    • Download issued certificate, double-click to install
    • Note your Team ID and certificate name

The certificate name is what goes into --sign "Certificate Name".

Prerequisite: Xcode Tools

Install Xcode command line tools:

xcode-select --install

# Verify xcrun is available
xcrun --version

Store notarization credentials once:

xcrun notarytool store-credentials "notarytool-profile" \
 --apple-id "your@apple-id.com" \
 --team-id "YOUR_TEAM_ID" \
 --password "app-specific-password"

⚠️ The password is an app-specific password from appleid.apple.com, not your regular Apple ID password.

Finally, what we actually wanted to do

# Sign the app
codesign --force --deep --timestamp --options runtime \
 --sign "Developer ID Application: Your Name (TEAM_ID)" \
 "myapp.app"

# Zip for notarization
zip -r "myapp.app.zip" "myapp.app"

# Submit for notarization (1-3 minutes typically)
xcrun notarytool submit "myapp.app.zip" \
 --keychain-profile "notarytool-profile" --wait

# Success looks like:
# "Processing complete. Submission ID: xxx-xxx-xxx"
# "status: Accepted"

# Staple the notarization
xcrun stapler staple "myapp.app"

# Clean up and create final distributable
rm "myapp.app.zip"
zip -r "myapp-signed.zip" "myapp.app"

Troubleshooting

  • "no identity found" → Certificate not installed or wrong name
  • "invalid signature" → Try --deep flag, check entitlements
  • Notarization rejected → Check for unsigned dependencies with:

codesign -dv --verbose=4

Closing Note

The setup is painful once – trivial afterwards.
The $99 is Apple’s developer tax: pay it, or stick to localhost.

About the Author

Alessandro is a technical mastermind and Chief Technology Officer at Iridium Works. Over the years he has build countless systems working with Front- and BackEnd, DevOps and as a Tech Lead. He writes about new technology, software development.

Alessandro Frank
CTO
at Iridium Works
📍
Koblenz, Germany
🔗
Full Biogrpahy
🔗
LinkedIn Profile
Let's build your digital future, together.
We build digital experiences for pioneers that want to challenge the status quo so that they can rise to the top of their competitive landscape.
Text reading 'Iridium Works' with a blue marbled texture fill on a transparent background.
Black and white close-up portrait of a man with a bald head, full beard, and checkered shirt looking directly at the camera.
Portrait of a woman with long dark hair, wearing black glasses, a black blazer, and a light gray top, against a plain gray background.
Smiling bald man with a beard wearing a white dress shirt with his arms crossed, standing against a dark blue textured wall.
Smiling man wearing glasses, a navy blazer, white shirt, and jeans, sitting on a wooden stool against a plain background.
Young man with glasses, beige zip-up sweater, white shirt, and gray pants sitting on a wooden stool against a light gray background.
© Iridium Works GmbH. All rights reserved.
Welcome to digital excellence.