This guide walks you through setting up code signing and notarization for twig on macOS.
- Apple Developer Account (you have this ✓)
- Xcode Command Line Tools installed
- Developer ID Application Certificate in your Keychain
- Go to https://developer.apple.com/account
- Sign in with your Apple ID
- Your Team ID is displayed in the top right (10-character string like
ABCDE12345)
If you haven't already:
- Go to https://developer.apple.com/account/resources/certificates/list
- Click the + button to create a new certificate
- Select Developer ID Application
- Follow the steps to generate a Certificate Signing Request (CSR)
- Download and double-click the certificate to install it in your Keychain
Verify installation:
security find-identity -v -p codesigningYou should see a line like:
1) ABCDEF1234567890... "Developer ID Application: Your Name (TEAM_ID)"
- Go to https://appleid.apple.com
- Sign in with your Apple ID
- In the Security section, click App-Specific Passwords
- Click Generate an app-specific password
- Give it a label like "twig Notarization"
- Copy the generated password (format:
xxxx-xxxx-xxxx-xxxx)
Important: Save this password securely! You won't be able to see it again.
-
Copy
.env.exampleto.env:cp .env.example .env
-
Edit
.envand fill in your values:APPLE_TEAM_ID=YOUR_TEAM_ID APPLE_ID=your.email@example.com APPLE_APP_SPECIFIC_PASSWORD=xxxx-xxxx-xxxx-xxxx
-
Never commit
.envto git! (already in.gitignore)
Build a release macOS package:
npm run build:mac:releaseThe build process will:
- Code sign the app with your Developer ID certificate
- Upload the app to Apple for notarization
- Wait for Apple's approval (usually 1-5 minutes)
- Staple the notarization ticket to the app
- Make sure your Developer ID certificate is installed in Keychain
- Run
security find-identity -v -p codesigningto verify
- Double-check your
APPLE_IDandAPPLE_APP_SPECIFIC_PASSWORD - Make sure you're using an app-specific password, not your regular Apple ID password
- Apple's servers can be slow sometimes
- The build will wait up to 30 minutes by default
- Check status at https://developer.apple.com/account/resources/notarization/list
- The entitlements file (
build/entitlements.mac.plist) allows necessary exceptions - Required for Electron apps using JIT compilation and native modules
For automated builds (GitHub Actions, etc.):
- Store secrets as environment variables in your CI system
- For the certificate, you'll need to:
- Export it from Keychain as a
.p12file - Base64 encode it
- Store as
CSC_LINK(base64 string) andCSC_KEY_PASSWORD(p12 password)
- Export it from Keychain as a
Example GitHub Actions:
- name: Build macOS app
env:
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
CSC_LINK: ${{ secrets.CSC_LINK }}
CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }}
run: npm run build:mac- ✓ App ID changed to
com.twig.app - ✓ Hardened Runtime enabled
- ✓ Notarization configured in
electron-builder.yml - ✓ Entitlements file for necessary exceptions
- ✓ Environment variable template in
.env.example - ✓
.envadded to.gitignore