How to sign and notarize an Electron app for macOS
May 15, 2024
May 15, 2024
So you made a macOS app, shared it with your friends, and they encountered one of those dreaded popups:
Then you need to sign (left) and notarize (right) your app!
Note: in the meantime, the app can still be opened by right clicking on it and clicking Open from the context menu.
Signing consists in buying a developer membership with Apple, which will
let you create a key that you can use to codesign your app with.
Notarizing consists in uploading your app to an Apple service that scans it for malware. If it passes the process, your app gets a âstamp of approvalâ that is bundled with your app and also mirrored on Appleâs Gatekeeper servers.
In the case of Electron, hereâs some relevant docs this article is based on:
The first step is to generate a signing keypair, and get a signing certificate from Apple, which requires you to subscribe to Appleâs developer program.
Then, follow create a certificate signing request.
In my experience, it doesnât seem that the User Email Address you input matters.
As for Common Name, it seems to only affect how the private and public key are named in Keychain Access.
By saving the request to disk, you will get a
CertificateSigningRequest.certSigningRequest file.
This will also create a Common Name.p12 and Common Name.pem entry in
your Keychain Access. The .p12 is the private key, and the .pem is
the public key, that are going to be associated with the certificate
youâre requesting.
You should now upload the .certSigningRequest file to your Apple
Developer account, in Certificates, IDs & Profiles. Choose the
Developer ID Application certificate type.
This will give you a certificate developerID_application.cer that you
need to import in Keychain Access (by simply opening it).
Note: if it refuses to open with âThe System Roots keychain cannot
be modifiedâ, itâs because Keychain Access opens by default in the
System Roots keychain and you can only update it as superuser (so mainly
from the CLI with sudo security ...).
We only need this certificate in the login keychain, so make sure itâs the selected one in Keychain Access and then open the certificate again.
In Appleâs PKI, your developer certificate is signed by an intermediate certificate, thatâs itself signed by one of Appleâs root certificates.
The Apple root certificates should already be present out of the box in
your System Roots keychain, but the intermediate ones are not, and need
to be downloaded for the certificate chain to be complete and for
codesign to work.
When you created your Developer ID certificate, you were likely prompted between âG2 Sub-CAâ and âPrevious Sub-CAâ. At the time of writing, on the Apple PKI page, those are respectively Developer ID - G2 (Expiring 09/17/2031 00:00:00 UTC) and Developer ID - G1 (Expiring 02/01/2027 22:12:15 UTC). So go ahead and download the appropriate one and install it to your login keychain just like your developer certificate.
Note: if you donât know what intermediate certificate you need, you can see what CA signed your certificate like so:
$ openssl x509 -in "developerID_application.cer" -noout -issuer
issuer=CN=Developer ID Certification Authority, OU=G2, O=Apple Inc., C=US
In this case, you can see my certificate was issued using the G2 intermediate certificate.
Warning: leave the certificate trust settings to âUse System Defaultsâ and do not mark it as âAlways Trustâ, both for your developer certificate and the intermediate certificate.
If like me you were getting issues signing things and assumed marking as
âAlways Trustâ could help, beware, it does the opposite and prevents
codesign from working altogether for some reason, even after you fix
the actual cause of your signing issues. đ
Whether youâre missing a certificate, or if you have the right certificates but theyâre marked as âAlways Trustâ, youâll get that same error:
Warning: unable to build chain to self-signed root for signer
Youâre now in a place where you can manually sign your app:
codesign --sign 'Developer ID Application: MyApp (ID)' MyApp.app
To find the identify to pass to --sign:
security find-identity -v -p codesigning
-v will show only valid identities. -p is for selecting a specific
policy, here we care about codesigning.
Add osxSign to your forge.config.js:
module.exports = {
packagerConfig: {
osxSign: {
identity: 'Developer ID Application: MyApp (ID)'
}
}
}
If you only have one valid code signing identity configured on your Mac,
you can omit the identity parameter. You still need to pass an empty
object osxSign: {}.
Add osxNotarize to your forge.config.js. Thereâs a few ways to
configure it documented here.
The documentation is pretty clear and complete so I wonât bother repeating anything here. đ
osxSign and osxNotarizeIf you encounter issues where Electron is not properly signing or notarizing your app, you can debug the signing and notarizing process that way:
DEBUG=electron-osx-sign,electron-notarize* npx electron-forge package
This will output detailed logs that should help you identify the culprit.
That should be all you need to have your app approved by Apple so that you can share it with the world. đ
Happy building! đ