Library / SDK
electron/osx-sign avatar
electron/osx-sign

@electron/osx-sign: What the Signing Wrapper Actually Does to Your .app

Codesign Electron macOS apps

631 stars113 forksTypeScriptBSD-2-Clause

At a glance

What is it?
@electron/osx-sign wraps the macOS codesign and productbuild utilities for Electron apps, adding entitlement handling and provisioning profile lookup. It is a thin layer over Apple tooling, and its defaults encode opinions about Mac App Store submission that you need to understand before you run it.
Who is it for?
Adopt it if you ship an Electron app to the Mac App Store, or outside it via Developer ID, and you want entitlement injection and provisioning profile lookup handled rather than scripted by hand. Do not adopt it if you need fine-grained control over every codesign invocation, because the defaults for distribution builds deliberately produce an app that will not launch locally.
Can I use it commercially?
Yes. BSD-2-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 5 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The gap between a packaged Electron app and a distributable one

Electron Packager and Electron Forge produce a .app bundle. Apple's Gatekeeper does not care that the bundle was produced correctly; it cares that every nested binary, framework and helper carries a valid signature, and that the signature matches the entitlements Apple expects for the distribution channel you chose. Doing that by hand means walking the bundle, calling codesign in the right order with the right flags, and injecting entitlements that differ between Mac App Store and Developer ID distribution. @electron/osx-sign exists to absorb that work. The README states the package "minimizes the extra work needed to eventually prepare your apps for shipping, providing options that work out of the box for most applications." The audience is narrow and specific: developers who already have an Apple Developer Program membership, Xcode, and a packaged Electron app. If you are not distributing on macOS, this package has nothing to offer you.

Two entry points: sign for codesign, flat for productbuild

The package exposes two distinct capabilities. The README describes them plainly: signing macOS apps via sign functions, which call the codesign utility under the hood, and creating .pkg installer packages via flat functions, which call productbuild. That split matters because they solve different problems. sign produces a signed .app bundle, which is what you need for direct distribution or for uploading to App Store Connect. flat produces an installer package, which is what you need when your distribution path runs through a .pkg rather than a zipped bundle. The README does not document the flat API in the section reproduced here beyond naming it, so if your pipeline depends on .pkg output you will be reading the linked API documentation rather than the README. Treat the signing path as the documented, primary surface and the packaging path as the secondary one.

What preAutoEntitlements changes, and why distribution builds stop launching

This is the most consequential default in the package and the one most likely to confuse a first-time user. According to the README, @electron/osx-sign adds the entry com.apple.developer.team-identifier to a temporary copy of your specified entitlements file. That happens under the default option preAutoEntitlements. The README then states the consequence directly: distribution builds can no longer be run directly. This is not a bug and it is not an accident of configuration. It is the expected outcome of a build intended only for submission to App Store Connect. The README also notes that the app is not expected to run after codesigning since there is no provisioned device. If your workflow assumes you can sign a distribution build and then double-click it to sanity-check the UI, that assumption breaks here. The documented workarounds are to set type to development, which produces an app that runs on your provisioned machine but is ineligible for App Store Connect submission, or to manually add ElectronTeamID to Info.plist and com.apple.security.application-groups to the entitlements file while setting preAutoEntitlements to false. The second path is more work and the README points to Apple's Technical Note TN2415 for the rule that certain features are only allowed across apps whose team-identifier value matches.

Getting it running: install, options, and the per-file escape hatch

Installation is a single dev dependency: npm install --save-dev @electron/osx-sign. If you use Electron Packager or Electron Forge, the README says the package is integrated into both and can be configured through their respective option surfaces, so you may never call it directly. Calling it directly means importing sign and passing an options object. The only mandatory option is app, a path to your .app package. For Mac App Store work the README's example passes platform: "mas", type: "distribution", provisioningProfile: 'path/to/my.provisionprofile', and keychain: 'my-keychain'. The defaults are worth memorizing: type defaults to distribution, provisioningProfile defaults to the current working directory, and keychain defaults to the system default login keychain. The README recommends placing the distribution provisioning profile in the current working directory and installing the signing identity in the default keychain, which means a correctly prepared machine needs no explicit paths at all. For subresources that need signing with --deep, the optionsForFile callback receives a filePath and a context object containing the resolved platform, and returns extra options merged into that file's signing operation. The README is explicit that --deep is "not typically safe to apply to the entire Electron app" and should be applied to just the file that needs it. That callback is the intended mechanism for scoping it.

The certificate and profile prerequisites are the real cost

Nothing in this package removes the Apple-side setup. You need a registered Apple Developer Program membership, and the README notes you could be charged by Apple for the required certificates. You need Xcode installed from the Mac App Store, with the README advising against third-party downloads for security reasons, plus the Xcode Command Line Tools, checkable with xcode-select --install. For Mac App Store distribution you need a Mac App created in App Store Connect, a unique Bundle ID, and a version number. The certificate pairs differ by channel: Mac App Distribution and Mac Installer Distribution for the App Store, Developer ID Application and Developer ID Installer for outside it. The README's tip is that the pairs tend to come together and it is simplest to install both, but if you only distribute outside the Mac App Store you do not need the 3rd Party Mac Developer certificates installed. This is the part of the workflow that consumes the most calendar time, and no wrapper library shortens it.

Where it is the wrong tool

The package assumes a conventional Electron bundle layout and a conventional signing chain. If your app embeds a helper process that needs its own provisioning profile, or if you are signing nested content that Apple's notarization flow treats specially, the defaults may not cover you and you will be reaching for optionsForFile or bypassing the tool. The --deep guidance is a signal here: the README treats deep signing as something to apply surgically, which means the package does not attempt to decide for you which subresources need it. If you want a tool that inspects your bundle and tells you what to sign, this is not that tool. It also does not notarize. Signing and notarization are separate steps in Apple's pipeline, and the README reproduced here does not describe a notarization capability, so you should not expect one. Finally, if you are not on macOS or not distributing there, the entire package is inapplicable, and the TypeScript implementation does not change that.

How it compares to hand-rolled codesign scripting and to electron-builder

The alternative most teams weigh is a shell script that calls codesign directly. That approach gives you total control over flag order and per-file treatment, and it never surprises you with an entitlement you did not add. The cost is that you own the entitlement injection logic, the provisioning profile lookup, and the platform detection that @electron/osx-sign performs. electron-builder is the other real alternative, and the difference in approach is structural: electron-builder is a full packaging and distribution tool that includes macOS signing as one stage among many, while @electron/osx-sign is a signing and packaging utility that other tools call into. The README lists Electron Forge and Electron Packager as integrations, which places @electron/osx-sign in the role of a shared lower layer rather than a competing pipeline. If you already use electron-builder, adding @electron/osx-sign separately would duplicate work. If you use Forge or Packager, it is already in your path.

Maintenance, licensing, and what to check before you commit

The package is published under BSD-2-Clause, a permissive licence that imposes minimal obligations; it is not a copyleft licence, but you should read the actual terms rather than rely on that summary, and this is not legal advice. The repository is active, not archived, with releases v2.6.0 in July 2026, v2.6.2 and v2.7.0 in August 2026, and a last push in September 2026. Those dates tell you the project is receiving attention; they do not tell you whether a future macOS or Xcode change will break it, and since the package shells out to codesign and productbuild, Apple's tooling changes are the real risk surface. The version numbers are in the 2.x line, so expect minor releases rather than a stable 3.x contract. Before adopting, confirm three things on your own machine: which certificates are installed in which keychain, whether your provisioning profile is in the working directory or needs an explicit path, and whether your distribution workflow can tolerate an app that will not launch locally after signing. That last point is the one that catches people, and it is documented behaviour rather than a defect.

Editorial conclusion

Adopt it if you ship an Electron app to the Mac App Store, or outside it via Developer ID, and you want entitlement injection and provisioning profile lookup handled rather than scripted by hand. Do not adopt it if you need fine-grained control over every codesign invocation, because the defaults for distribution builds deliberately produce an app that will not launch locally. Before your first release, verify which certificates are in your keychain, confirm whether your provisioning profile sits in the working directory or needs an explicit provisioningProfile path, and decide whether preAutoEntitlements should stay true.

Official sources

  1. electron/osx-sign on GitHub
  2. Issues
  3. License: BSD-2-Clause
  4. README
  5. Releases
Community notes

Community notes