13 KiB
Update macOS certificates for electron-builder
Mac access required! The instructions below refresh every asset used by the GitHub Actions/macOS runners for Mac App Store (MAS) and direct-download (DMG) builds.
Certificates
1. Clean up old material
⚠️ Note: Deleting old certificates also removes their private keys. If you don’t have the private key backed up, generate a new CSR before creating new certificates (so maybe we should not delete the certificates too early?).
- In https://developer.apple.com/account/resources/certificates/list, revoke the expiring certificates so they cannot be downloaded again by accident.
- Remove the matching identities from your local keychain (
Keychain Access → My Certificates-open -a "Keychain Access") so you do not export the wrong private key later.
2. Create a fresh CSR (once)
- Open Keychain Access → Certificate Assistant → Request a Certificate From a Certificate Authority…
- Enter the Apple ID email tied to the team, select “Saved to disk”, and pick a location for
mac-dev-team.csr. - Repeat only if you need a CSR for a different Apple ID/team.
3. Generate the required certificates
Create the following certificates in the developer portal, using the CSR from step 2:
- Apple Development – used for local development/debug builds.
- Apple Distribution (Apple renamed “Mac App Distribution”) – used to sign the MAS app.
- Mac Installer Distribution – used to sign the MAS
.pkgthat is uploaded via Transporter. - Developer ID Application – used to sign the notarized DMG build.
- Developer ID Installer – used if you ship a signed installer
.pkgfor DMG distribution (still required by electron-builder whendist:mac:dlruns). Download each resulting.cerfile and note the exact label Apple shows so you can cross-check in CI logs later.
4. Install and export as PKCS#12
- Double-click every downloaded
.cerso it lands inside the login keychain under “My Certificates”. You should now see each certificate with a disclosure triangle that reveals the paired private key—if the triangle is missing, delete the cert and regenerate it so the private key attaches properly. - Multi-select the identities listed above (adjust if you only target MAS or only Developer ID), right-click → Export Items…, save as
all-certs.p12, and choose a strong password (this password becomes theMAC_CERTS_PASSWORD). Confirm the repeated macOS password prompts.- Alternatively, run:
security export -k ~/Library/Keychains/login.keychain-db \ -t identities -f pkcs12 -P "$MAC_CERTS_PASSWORD" \ -o all-certs.p12
- Alternatively, run:
- Verify you can re-import
all-certs.p12onto another Mac before proceeding.
5. Prepare CI secrets
- Base64 the exported file:
base64 -i all-certs.p12 -o all-certs.b64. - Update the GitHub Actions secret
MAC_CERTSwith the contents ofall-certs.b64and the secretMAC_CERTS_PASSWORDwith the password chosen above. - Map those secrets to electron-builder’s expectations inside your workflow, for example:
UseCSC_LINK: ${{ secrets.MAC_CERTS }} CSC_KEY_PASSWORD: ${{ secrets.MAC_CERTS_PASSWORD }} CSC_IDENTITY_AUTO_DISCOVERY: trueCSC_INSTALLER_LINK/CSC_INSTALLER_KEY_PASSWORDif you decide to store installer identities separately. - If you prefer keeping separate secrets, repeat the export step per certificate and upload them with names such as
MAC_DISTRIBUTION_CERT, but the current workflow expects a single bundle. Whatever approach you choose, ensure the CI job imports the PKCS#12 into an unlocked keychain before invoking electron-builder.
Provisioning profiles
Important: create/refresh profiles after the new certificates exist, otherwise downloading the profile will still pull the revoked certs.
- Go to https://developer.apple.com/account/resources/profiles/list.
- Create two new profiles:
- Type “Mac App Store” → select the
Apple Distributioncertificate → choose the MAS App ID → download asmas.provisionprofile. - Type “Developer ID Application” → select the
Developer ID Applicationcertificate → choose the same App ID → download asdl.provisionprofile(optional for most Developer ID apps, but we keep it to satisfy older tooling and entitlements checks).
- Type “Mac App Store” → select the
- Move the files into
tools/mac-profiles/mas.provisionprofileandtools/mac-profiles/dl.provisionprofile(keep the exact filenames so the build scripts pick them up). If you skip the Developer ID profile, removetools/mac-profiles/dl.provisionprofileand clear theDL_PROVISION_PROFILEsecret so CI doesn’t look for it. - Base64-encode them for CI:
base64 -i tools/mac-profiles/dl.provisionprofile -o dmg-profile.b64 base64 -i tools/mac-profiles/mas.provisionprofile -o mas-profile.b64 - Update the GitHub secrets
DL_PROVISION_PROFILE(dmg) andMAS_PROVISION_PROFILE(store) with the encoded strings and ensure the workflows pass them to electron-builder (e.g.,build.mac.provisioningProfile). Remember to keep hardened runtime enabled (build.mac.hardenedRuntime=true) and entitlements aligned for notarization.
See also:
- https://www.electron.build/code-signing.html
- https://www.electronjs.org/docs/tutorial/mac-app-store-submission-guide
Build the DMG locally
- Create or refresh an app-specific password at https://appleid.apple.com/account/manage (use the same Apple ID as notarization).
- Confirm your scripts use
xcrun notarytool(Apple blockedaltooluploads as of 2023‑11‑01). electron-builder defaults tonotarytoolwhen it detects Xcode 14+, so avoid overriding that behavior. - Run:
APPLEID="you@example.com" \ APPLEIDPASS="app-specific-password" \ rm -Rf app-builds && npm run build && npm run dist:mac:dl - The script signs, notarizes (via
notarytool), and staples the DMG using the new certificates and provisioning profiles. Validate withspctl --assess -vv --type install path/to/app.
macOS App Store Certificates Guide
(Local + CI workflow with electron-builder — 2025 edition)
1) Overview
To build and publish your Electron app to the Mac App Store (MAS), you need these certificates and a provisioning profile:
| Item | Purpose | Used in |
|---|---|---|
| Apple Development | Sign local debug/test builds | Local only |
| Apple Distribution | Sign the App Store .app |
Local + CI |
| Mac Installer Distribution | Sign the .pkg uploaded via Transporter |
Local + CI |
| Mac App Store provisioning profile | Ties the App ID to Apple Distribution | Local + CI |
You do not need Developer ID certificates or notarization for MAS-only distribution.
2) Generate a new CSR (Certificate Signing Request)
- On your Mac, open Keychain Access → Certificate Assistant → Request a Certificate From a Certificate Authority…
- Fill in:
- User Email Address: your Apple ID for the developer team
- Common Name: e.g.
Super Productivity MAS Signing Key - CA Email Address: leave blank
- Request is: Saved to disk
-
Save as
mac-mas.csr.This also creates a private key in your login keychain.
3) Create the MAS certificates in the Apple Developer Portal
- Go to https://developer.apple.com/account/resources/certificates/list → ➕ Add
- Create each certificate using
mac-mas.csr:
- Apple Development (for local testing)
- Apple Distribution (replaces “Mac App Distribution”)
- Mac Installer Distribution (required for
.pkgupload)
- Download each resulting
.cerfile.
4) Install and export the identities (for local and CI)
- Install: Double-click each
.certo add it under Keychain Access → My Certificates.
- Each entry must show a disclosure triangle with a private key.
- If the private key is missing, regenerate the CSR and certificate.
- Export: Select the relevant identities → right-click → Export …
- Format: Personal Information Exchange (.p12)
- Name:
mas-certs.p12 - Set a strong password (→
MAC_CERTS_PASSWORD).
-
Verify on a second Mac (optional but recommended):
security import mas-certs.p12 -k login.keychain-db -P "$MAC_CERTS_PASSWORD" security find-identity -v -p codesigningYou should see Apple Distribution and Mac Installer Distribution.
5) Create / refresh the Mac App Store provisioning profile
- Go to https://developer.apple.com/account/resources/profiles/list → ➕ Add Profile
- Profile type: Mac App Store
- Select:
- Apple Distribution certificate
- Your App ID
-
Download as
mas.provisionprofile. -
Place it in your repo, e.g.:
tools/mac-profiles/mas.provisionprofile
6) Configure electron-builder
In electron-builder.yml or package.json > build:
mac:
category: public.app-category.productivity
hardenedRuntime: true
provisioningProfile: tools/mac-profiles/mas.provisionprofile
entitlements: build/entitlements.mas.plist
entitlementsInherit: build/entitlements.mas.inherit.plist
target:
- mas
Ensure your MAS entitlements files are correct and compatible with App Store requirements.
7) Local build (MAS)
With the identities installed in your keychain:
npm run build && npm run dist:mac:mas
Result: dist/mac/YourApp.pkg — signed and ready for App Store upload.
8) Prepare CI secrets
Base64-encode the cert bundle and profile:
base64 -i mas-certs.p12 -o mas-certs.b64
base64 -i tools/mac-profiles/mas.provisionprofile -o mas-profile.b64
Create GitHub Actions secrets (Repo → Settings → Secrets and variables → Actions):
| Secret | Value |
|---|---|
MAC_CERTS |
contents of mas-certs.b64 |
MAC_CERTS_PASSWORD |
the .p12 export password |
MAS_PROVISION_PROFILE |
contents of mas-profile.b64 |
APPLE_APP_SPECIFIC_PASS |
Apple ID app-specific password (for upload tooling) |
9) GitHub Actions workflow (example)
name: Build macOS MAS
on:
workflow_dispatch:
push:
tags:
- 'v*'
jobs:
build-mas:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- name: Decode certificates
run: echo "${{ secrets.MAC_CERTS }}" | base64 --decode > mas-certs.p12
- name: Create and unlock keychain
run: |
security create-keychain -p "" build.keychain
security import mas-certs.p12 -k build.keychain -P "${{ secrets.MAC_CERTS_PASSWORD }}" -T /usr/bin/codesign -T /usr/bin/security
security set-key-partition-list -S apple-tool:,apple: -s -k "" build.keychain
security list-keychains -s build.keychain
security default-keychain -s build.keychain
security unlock-keychain -p "" build.keychain
security find-identity -v -p codesigning build.keychain
- name: Write provisioning profile
run: echo "${{ secrets.MAS_PROVISION_PROFILE }}" | base64 --decode > tools/mac-profiles/mas.provisionprofile
- name: Install dependencies
run: npm ci
- name: Build & sign for MAS
env:
CSC_LINK: ${{ secrets.MAC_CERTS }}
CSC_KEY_PASSWORD: ${{ secrets.MAC_CERTS_PASSWORD }}
CSC_IDENTITY_AUTO_DISCOVERY: true
APPLEID: you@example.com
APPLEIDPASS: ${{ secrets.APPLE_APP_SPECIFIC_PASS }}
run: npm run build && npm run dist:mac:mas
The
set-key-partition-liststep grants non-interactive access to the private keys forcodesignduring CI.
10) Upload to App Store Connect
- Find the generated
.pkgindist/. - Upload with Transporter (Apple’s tool):
- Open Transporter, sign in with your Apple ID
- Drag the
.pkgand click Deliver
-
Optional verification:
pkgutil --check-signature path/to/YourApp.pkgExpect:
Signed by "Apple Mac Installer Distribution: <Your Team>" Status: signed Apple Software
11) Maintenance & rotation
-
Certificates typically expire after 1 year (some teams may have 3-year certs).
-
Before expiry, repeat this guide:
- Revoke/replace Apple Distribution and Mac Installer Distribution
- Recreate the Mac App Store provisioning profile
- Export a new
mas-certs.p12, update CI secrets, and (if needed) reimport locally
-
Keep your App-Specific Password valid for uploads.
Quick Reference (What you actually need for MAS)
- Certificates: Apple Development (local), Apple Distribution, Mac Installer Distribution
- Profile: Mac App Store provisioning profile
- No Developer ID / notarization needed for MAS-only
- Build target:
mas - Upload:
.pkgvia Transporter