macOS Code Signing

A step‑by‑step guide to code signing and notarizing Tauri v2 applications for macOS, so users can open your app without Gatekeeper warnings.

When you build a Tauri app and send the .dmg to someone, macOS will often block it with a message that the app is damaged or from an unidentified developer. That is Gatekeeper acting on a missing code signature and notarization ticket. Signing your app proves who built it and that it hasn’t been tampered with. Notarization is Apple’s separate malware scan that attaches a trust ticket to the signed app.

This guide covers everything you need — from creating an Apple Developer certificate through to notarizing the final binary — so your Tauri v2 app launches on other people’s Macs without workarounds. Pair it with macOS packaging.

Why macOS Requires Code Signing

Gatekeeper is the subsystem on macOS that checks every app before it launches. If the app was downloaded from the internet, Gatekeeper looks for a valid code signature that chains to a certificate issued by Apple. Without it, users see the “damaged” dialog and can’t open the app unless they manually override security settings.

Even if you sign the app, macOS Catalina (10.15) and later also require notarization for software distributed outside the Mac App Store. Notarization is an automated scan performed on Apple’s servers. Once the scan passes, Apple staples a ticket to the app bundle, and Gatekeeper allows it to run without complaints.

Think of code signing as a tamper‑proof ID card, and notarization as a background check. You need both for a smooth distribution experience on modern macOS.

Does my app need this?:

If you only ever run the app on your own development machine, ad‑hoc signing is enough (see the section on ad‑hoc signing). For anyone else to open it — colleagues, testers, or public users — you must have a proper Apple‑issued signing identity and notarization.

Prerequisites

  • A paid Apple Developer Program membership ($99/year). The free tier can create certificates for development and testing, but cannot notarize apps for distribution. You can enrol at developer.apple.com/programs/enroll.
  • A Mac where you perform the signing. Apple’s tools require macOS to generate certificates and run codesign.
  • Xcode (or the Xcode Command Line Tools) installed. The notarization tooling and code signing utilities come with Xcode.
  • A Tauri v2 project that builds successfully with npm run tauri build before you add signing.

Creating a Developer ID Application Certificate

For apps distributed outside the Mac App Store, you need a Developer ID Application certificate. Only the Account Holder role can create this certificate type. If you are on a team, the account holder must perform these steps.

1

Generate a Certificate Signing Request (CSR)

On your Mac, open Keychain Access. From the menu bar, select Keychain Access > Certificate Assistant > Request a Certificate From a Certificate Authority. Enter your Apple ID email, leave the CA Email field empty, choose Saved to disk, and save the .certSigningRequest file.

2

Upload the CSR to Apple Developer

Go to the Certificates, Identifiers & Profiles page on the Apple Developer portal. Click the + button to create a new certificate. Select Developer ID Application and click Continue. Upload the .certSigningRequest file you just saved.

3

Download and install the certificate

After the certificate is generated, click Download to get the .cer file. Double‑click the .cer file to install it into your login keychain. You should see a new entry under My Certificates in Keychain Access labelled “Developer ID Application: Your Name (TEAMID)”.

Finding Your Signing Identity

The signing identity is the string that codesign uses to locate your certificate. After installation, run this command in the terminal:

security find-identity -v -p codesigning

You will see output similar to:

1) ABC123DEF456... "Developer ID Application: Your Name (TEAMID)"

The quoted string — "Developer ID Application: Your Name (TEAMID)" — is your signing identity. Copy it; you will need it in the Tauri configuration.

Entitlements for Tauri's WebView

Tauri uses a system WebView, which relies on Just‑In‑Time compilation and writable executable memory for its JavaScript engine. Apple’s Hardened Runtime restricts both by default, so you must grant these capabilities through an entitlements file.

Create src-tauri/Entitlements.plist with the following content:

src-tauri/Entitlements.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
  "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>com.apple.security.cs.allow-jit</key>
    <true/>
    <key>com.apple.security.cs.allow-unsigned-executable-memory</key>
    <true/>
</dict>
</plist>

The two keys work together: allow-jit enables the JavaScript engine’s JIT compiler, and allow-unsigned-executable-memory lets it allocate memory pages that it can mark as executable on the fly. Without these entitlements, the WebView will crash during notarization or at runtime on hardened systems.

Configuring Tauri for macOS Signing

Add the signing identity and entitlements path to your tauri.conf.json inside the bundle.macOS section. The configuration file is located at src-tauri/tauri.conf.json.

src-tauri/tauri.conf.json
{
  "bundle": {
    "macOS": {
      "signingIdentity": "Developer ID Application: Your Name (TEAMID)",
      "entitlements": "./Entitlements.plist",
      "minimumSystemVersion": "11.0",
      "dmg": {
        "appPosition": { "x": 180, "y": 170 },
        "applicationFolderPosition": { "x": 480, "y": 170 }
      }
    }
  }
}

The minimumSystemVersion field sets the lowest macOS version your app supports. Big Sur (11.0) is a reasonable floor for modern Tauri apps. The dmg positioning values control where the app icon and the Applications shortcut appear in the DMG window; they are optional but improve the user experience.

The signing identity can be placed directly in the signingIdentity field as shown above. Tauri reads it at build time and passes it to the macOS code signing tools.

Hardened Runtime is enabled automatically:

Tauri enables the Hardened Runtime (--options runtime) for signed apps by default. You do not need to set hardenedRuntime: true manually unless you have a very specific override. Setting it unnecessarily can cause confusion later.

Notarizing Your Application

After Tauri signs the .app bundle, it can automatically submit the binary to Apple for notarization. You need to provide credentials so Tauri can authenticate with Apple’s servers. There are two ways to do this.

This approach works well for individual developers. You generate an app‑specific password that is separate from your main Apple ID password.

  1. Go to appleid.apple.com, sign in, and navigate to Sign‑In and Security > App‑Specific Passwords.
  2. Generate a new password (name it “Tauri Notarization”).
  3. Find your Team ID on the Membership page of the Apple Developer portal. It is a 10‑character alphanumeric string.
  4. Set the following environment variables before running tauri build:
export APPLE_ID="your-apple-id@email.com"
export APPLE_PASSWORD="xxxx-xxxx-xxxx-xxxx"   # the app‑specific password
export APPLE_TEAM_ID="ABCDE12345"

Tauri picks up these variables automatically and uses them for notarization.

Once the credentials are set, run your normal build command:

npm run tauri build -- --bundles dmg

Tauri will sign the app, create a .dmg, and then notarize it. If the notarization succeeds, Apple staples the ticket to the bundle and the .dmg is ready for distribution.

How to know it worked:

After a successful build, open the .dmg file on another Mac (or a fresh user account). If the app launches without Gatekeeper warnings, notarization succeeded. You can also verify manually with spctl -a -vvv -t install MyApp.app — it should report accepted and show a valid notarization source.

Exporting Your Certificate for CI/CD

When building on a CI service like GitHub Actions, the signing certificate is not installed in the runner’s keychain by default. You need to export it from your Mac, encode it, and inject it as a secret.

1

Export the certificate and private key

Open Keychain Access, click My Certificates under the login keychain, and find your “Developer ID Application” entry. Expand it so the private key underneath is visible. Right‑click the private key (not the certificate) and select Export. Choose the .p12 format and set a strong password.

2

Convert to base64

Run this command to create a single‑line base64 representation of the .p12 file:

openssl base64 -A -in certificate.p12 -out certificate-base64.txt
3

Store as a secret

The contents of certificate-base64.txt become the APPLE_CERTIFICATE secret in your CI environment. Also store the export password as APPLE_CERTIFICATE_PASSWORD. Never commit these files to your repository.

A typical GitHub Actions step to import the certificate would look like this (using the secrets you configured):

github-actions
- name: Import Apple Developer Certificate
  env:
    APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
    APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
    KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
  run: |
    echo $APPLE_CERTIFICATE | base64 --decode > certificate.p12
    security create-keychain -p "$KEYCHAIN_PASSWORD" build.keychain
    security default-keychain -s build.keychain
    security unlock-keychain -p "$KEYCHAIN_PASSWORD" build.keychain
    security import certificate.p12 -k build.keychain -P "$APPLE_CERTIFICATE_PASSWORD" -T /usr/bin/codesign
    security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" build.keychain

This sequence creates a temporary keychain, imports your certificate into it, and makes it available to the codesign tool. With the signing identity set via environment variable or config, Tauri will use the imported certificate during the build.

Handling Sidecar Binaries

If your Tauri app embeds sidecar binaries (external executables configured via the externalBin option in tauri.conf.json or the shell plugin), those binaries must also be signed. Tauri signs the sidecar files automatically during the build, but the binaries must already be valid Mach‑O executables with a code signature that can be replaced.

Unsigned sidecars cause notarization failure:

Apple’s notarization service will reject the entire bundle if any embedded binary is unsigned or has an invalid signature. The error message often reads “The signature of the binary is invalid.” If you add a sidecar binary, build it with cargo build --release or sign it manually before including it, and ensure the binary path is correct so Tauri can locate and re‑sign it.

A common mistake is to copy a freshly compiled Rust sidecar binary without signing it first. Tauri will attempt to sign it, but if the binary was not built as a proper Mach‑O executable with space for a code signature header, the re‑signing may fail or produce an invalid signature. Always test your sidecar‑inclusive build on a separate machine before distributing.

Ad‑Hoc Signing for Local Testing

If you do not have an Apple Developer certificate and only need to run the app on your own Mac (or a colleague’s Mac with security settings relaxed), you can use ad‑hoc signing. Set the signing identity to a hyphen:

src-tauri/tauri.conf.json
{
  "bundle": {
    "macOS": {
      "signingIdentity": "-"
    }
  }
}

Ad‑hoc signing creates a local signature that proves the bundle hasn’t been modified, but it does not establish developer identity. On Apple Silicon Macs, code signing is required for all apps downloaded from the internet, so ad‑hoc signing at least satisfies that requirement during development. For any distribution to others, you must use a proper Developer ID certificate and notarization.

Common Mistakes and Troubleshooting

Using a free Apple Developer account for distribution:

The free tier cannot notarize applications. If you build with a Developer ID certificate from a paid account but authenticate notarization with a free‑tier Apple ID, notarization will fail with an authorization error. A paid membership is required.

Missing entitlements cause runtime crashes:

If you sign without the com.apple.security.cs.allow-jit and allow-unsigned-executable-memory entitlements, the WebView may crash on launch or during notarization validation. Always include the entitlements file and point to it in tauri.conf.json.

Forgetting to set environment variables:

Tauri will silently skip notarization if the required credentials are missing, and the build will succeed without producing a notarized app. Always double‑check that APPLE_ID, APPLE_PASSWORD, and APPLE_TEAM_ID (or the API key equivalents) are set before running tauri build when you intend to distribute the app.

Notarization takes time:

The notarization process can take several minutes, depending on Apple’s server load. The Tauri build will pause while waiting. If it times out, check the notarization status manually using xcrun notarytool history with your credentials.

A common failure scenario: you see “The signature of the binary is invalid” during notarization. This often means a nested executable or a sidecar binary was signed incorrectly. Re‑build the sidecar with a proper Rust target, ensure it is placed in the correct binaries directory, and run the build again. If the issue persists, check that the signing identity is available in the keychain that Tauri uses.

Summary

macOS code signing and notarization transform your Tauri v2 app from a blocked binary into a trusted application that launches without friction. The process revolves around a few concrete steps: obtain a Developer ID certificate, configure Tauri with that identity and the required WebView entitlements, and provide Apple ID or API key credentials for notarization.

The certificate proves authenticity; the entitlements let the WebView function under Hardened Runtime; and notarization gives macOS the green light. Once you have set this up, subsequent builds are repeatable — whether on your local machine or in CI.

The same Tauri configuration can be extended to support cross‑platform signing and distribution.