Electron macOS Desktop
Security Defaults (Required)
In BrowserWindow webPreferences:
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
preload: path.join(__dirname, 'preload.js'),
sandbox: true
}
Expose only specific APIs via contextBridge.exposeInMainWorld()—never expose raw ipcRenderer or require.
IPC Pattern
Preload – narrow API surface:
contextBridge.exposeInMainWorld('electronAPI', {
windowMinimize: () => ipcRenderer.invoke('window:minimize'),
getApiKey: () => ipcRenderer.invoke('settings:getApiKey'),
setApiKey: (key) => ipcRenderer.invoke('settings:setApiKey', key),
})
Main – handle and validate:
ipcMain.handle('settings:getApiKey', async () => { /* ... */ })
Sensitive Data Storage
Use safeStorage for secrets (API keys):
// main process
ipcMain.handle('settings:setApiKey', async (_, key) => {
const buf = safeStorage.encryptString(key.trim())
store.set('apiKeyEnc', buf.toString('base64'))
})
ipcMain.handle('settings:getApiKey', async () => {
const enc = store.get('apiKeyEnc')
if (!enc) return ''
return safeStorage.decryptString(Buffer.from(enc, 'base64'))
})
Store with electron-store; encrypt before save.
electron-builder macOS Config
mac:
target: [dmg]
category: public.app-category.developer-tools
hardenedRuntime: true
gatekeeperAssess: false
entitlements: build/entitlements.mac.plist
entitlementsInherit: build/entitlements.mac.plist
entitlements.mac.plist:
<key>com.apple.security.cs.allow-jit</key><true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key><true/>
<key>com.apple.security.cs.disable-library-validation</key><true/>
Content Security Policy
Update CSP for external APIs in both index.html and main process webRequest.onHeadersReceived:
connect-src 'self' https://api.example.com
macOS Window Behavior
app.on('window-all-closed'): ondarwin, do NOT callapp.quit()—macOS apps stay running.- Frameless window:
frame: false, custom title bar withWebkitAppRegion: 'drag'andno-dragon buttons.
Build Commands
pnpm run build && electron-builder --mac
Output: release/AppName-1.0.0-arm64.dmg. Set publish: null in config to skip auto-update publishing (avoids GH_TOKEN requirement).