{"id":37253462,"url":"https://github.com/vault12/electron-webauthn-mac","last_synced_at":"2026-01-17T02:00:49.813Z","repository":{"id":328201508,"uuid":"1113356614","full_name":"vault12/electron-webauthn-mac","owner":"vault12","description":"Native WebAuthn/Passkey support for Electron on macOS using Apple's AuthenticationServices framework","archived":false,"fork":false,"pushed_at":"2025-12-11T16:27:45.000Z","size":102,"stargazers_count":10,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-12-27T22:38:33.169Z","etag":null,"topics":["authenticationservices","electron","electron-addon","electron-builder","fido2","macos","passkey","webauthn"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vault12.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-09T21:39:36.000Z","updated_at":"2025-12-24T21:29:33.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/vault12/electron-webauthn-mac","commit_stats":null,"previous_names":["vault12/electron-webauthn-mac"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/vault12/electron-webauthn-mac","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vault12%2Felectron-webauthn-mac","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vault12%2Felectron-webauthn-mac/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vault12%2Felectron-webauthn-mac/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vault12%2Felectron-webauthn-mac/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vault12","download_url":"https://codeload.github.com/vault12/electron-webauthn-mac/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vault12%2Felectron-webauthn-mac/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28492047,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-17T00:50:05.742Z","status":"online","status_checked_at":"2026-01-17T02:00:07.808Z","response_time":85,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["authenticationservices","electron","electron-addon","electron-builder","fido2","macos","passkey","webauthn"],"created_at":"2026-01-15T18:00:21.239Z","updated_at":"2026-01-17T02:00:49.797Z","avatar_url":"https://github.com/vault12.png","language":"Swift","funding_links":[],"categories":["Tools","Client Libraries"],"sub_categories":["For Electron"],"readme":"# electron-webauthn-mac\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://github.com/user-attachments/assets/27ba0f24-f990-43d6-9edd-4dad8c06c0ba\"\n    alt=\"Electron Webauthn Mac\"\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cstrong\u003eNative WebAuthn/Passkey support for Electron on macOS\u003c/strong\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://www.electronjs.org\"\u003e\u003cimg src=\"https://img.shields.io/badge/electron-addon-blue?logo=electron\u0026logoColor=white\" alt=\"Electron Addon\" /\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/vault12/electron-webauthn-mac/releases\"\u003e\u003cimg src=\"https://img.shields.io/npm/v/electron-webauthn-mac\" alt=\"NPM Release\" /\u003e\u003c/a\u003e\n  \u003ca href=\"https://opensource.org/licenses/MIT\"\u003e\u003cimg src=\"https://img.shields.io/badge/License-MIT-blue.svg\" alt=\"MIT License\" /\u003e\u003c/a\u003e\n  \u003ca href=\"http://makeapullrequest.com\"\u003e\u003cimg src=\"https://img.shields.io/badge/PRs-welcome-brightgreen.svg\" alt=\"PRs Welcome\" /\u003e\u003c/a\u003e\n  \u003ca href=\"https://www.npmjs.com/package/electron-webauthn-mac\"\u003e\u003cimg src=\"https://img.shields.io/npm/dm/electron-webauthn-mac\" alt=\"Downloads\" /\u003e\u003c/a\u003e\n  \u003ca href=\"https://www.typescriptlang.org\"\u003e\u003cimg src=\"https://img.shields.io/badge/typescript-supported-blue?logo=typescript\u0026logoColor=white\" alt=\"Typescript\" /\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n## Contents\n\n- [Why This Addon?](#why-this-addon)\n- [Features](#features)\n- [Quick Start](#quick-start)\n- [Example Electron App](#example-electron-app)\n- [Configuring Entitlements and Domain Association](#configuring-entitlements-and-domain-association)\n- [Provisioning Profile Setup](#provisioning-profile-setup)\n- [API Reference](#api-reference)\n- [macOS Platform Quirks](#macos-platform-quirks)\n- [Troubleshooting](#troubleshooting)\n- [Plugin Development](#plugin-development)\n- [License](#license)\n\n## Why This Addon?\n\nThe [Web Authentication API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Authentication_API) `navigator.credentials` is the standard way to implement passkey authentication in web applications. However, in [Electron](https://www.electronjs.org) applications running on macOS, this API is currently broken and non-functional due to platform-specific limitations (see [electron/electron#24573](https://github.com/electron/electron/issues/24573)).\n\nThis addon serves as a native implementation and polyfill for macOS, providing direct access to Apple's [AuthenticationServices](https://developer.apple.com/documentation/authenticationservices/supporting-passkeys) framework. It allows Electron applications to use passkey authentication on macOS while maintaining the option to use the standard Web Authentication API on other platforms.\n\n## Features\n\n- **Platform \u0026 security key authenticators**: Support for Touch ID, iCloud Keychain, cross-device QR pairing, and external FIDO2 keys\n- **PRF extension**: Derive symmetric keys from passkeys for client-side encryption (platform authenticators only)\n- **LargeBlob extension**: Store and retrieve arbitrary data on the authenticator (platform authenticators only)\n- **System integration**: Open macOS password manager directly from your Electron app\n- **TypeScript support**: Full type definitions included\n\n## Quick Start\n\n### 1. Install the addon\n\n```bash\nnpm install electron-webauthn-mac\n```\n\n### 2. Use the API\n\nBasic example:\n\n```javascript\nconst webauthn = require('electron-webauthn-mac');\n\n// Create a new passkey\nasync function registerUser() {\n  try {\n    const credential = await webauthn.createCredential({\n      rpId: 'example.com', userId: 'user123', name: 'John', displayName: 'John Doe'\n    });\n    console.log('Created credential:', credential);\n  } catch (error) {\n    console.error('Registration failed:', error);\n  }\n}\n\n// Authenticate with an existing passkey\nasync function authenticateUser() {\n  try {\n    const assertion = await webauthn.getCredential({ rpId: 'example.com' });\n    console.log('Authentication successful:', assertion);\n  } catch (error) {\n    console.error('Authentication failed:', error);\n  }\n}\n```\n\n\u003e [!TIP]\n\u003e For cross-platform implementation, use the following pattern:\n\u003e ```javascript\n\u003e async function createPasskey(userId, userName, rpId) {\n\u003e   if (process.platform === 'darwin') { // Use native addon on macOS\n\u003e     const webauthn = require('electron-webauthn-mac');\n\u003e     return await webauthn.createCredential({ ... });\n\u003e   } else { // Use standard Web Authentication API on other platforms\n\u003e     return await navigator.credentials.create({ ... });\n\u003e   }\n\u003e }\n\u003e ```\n\n\u003e [!NOTE]\n\u003e **TypeScript** definitions are included. Import types directly:\n\u003e\n\u003e ```typescript\n\u003e import type {\n\u003e   CreateCredentialOptions, GetCredentialOptions,\n\u003e   RegistrationCredential, AssertionCredential\n\u003e } from 'electron-webauthn-mac';\n\u003e ```\n\n### 3. Configure the entitlements and domain association\n\nUnlike browser-based WebAuthn, macOS requires your app to prove it has association with the domain used as `rpId`. Follow the steps in [Configuring Entitlements and Domain Association](#configuring-entitlements-and-domain-association) to set this up. See [Why is domain association required?](#why-is-domain-association-required) for details.\n\n### 4. Sign and run the app\n\nYour Electron app must be code-signed to embed the entitlements from step 3 into the final `.app` bundle. Follow [Provisioning Profile Setup](#provisioning-profile-setup) to install the required provisioning profile. Running with `npm start` or `electron .` will launch the app, but passkey operations will fail because the unsigned process lacks an application identifier.\n\nUse a tool like [electron-builder](https://www.electron.build/) to build a signed `.app` bundle. See the [Example Electron App](#example-electron-app) for a working configuration.\n\n## Example Electron App\n\n\u003cimg width=\"300\" height=\"213\" align=\"right\" alt=\"Example Electron app\" src=\"https://github.com/user-attachments/assets/c528087e-85fa-4008-91fc-50bbf47aa379\" /\u003e\n\n\nThe repository includes an [example Electron application](example-electron-app/) demonstrating the addon usage. It shows how to expose the addon from the main process to the renderer thread using Electron's `contextBridge` and `ipcMain`/`ipcRenderer`.\n\n\u003e [!IMPORTANT]\n\u003e Before running the example app, complete [Configure the entitlements and domain association](#3-configure-the-entitlements-and-domain-association) and [Sign and run the app](#4-sign-and-run-the-app) from Quick Start.\n\n```bash\ncd example-electron-app\nnpm install\nnpm run build:mac\nopen dist/mac-arm64/WebAuthnDemo.app\n```\n\n## Configuring Entitlements and Domain Association\n\nFor WebAuthn to work with your domain (`rpId`), you must establish an association between your app and the domain. This is done by hosting an `apple-app-site-association` file on your server. See [Apple's Associated Domains documentation](https://developer.apple.com/documentation/xcode/supporting-associated-domains) for details.\n\n### 1. Find Your Team ID and Bundle ID\n\n- **Team ID**: Found in [Apple Developer Portal](https://developer.apple.com/account) → Membership Details\n- **Bundle ID**: Your app's bundle identifier (e.g., `com.yourcompany.yourapp`)\n\n### 2. Create the Association File\n\nHost an associated domain file on your website (with a URL such as `https://example.com/.well-known/apple-app-site-association`) with the following content:\n\n```js\n{\n  \"webcredentials\": {\n    \"apps\": [ \"TEAM_ID.BUNDLE_ID\" ] // Example: \"A1B2C3D4E5.com.example.myapp\"\n  }\n}\n```\n\n### 3. Confirm Server Requirements\n\nThe file must be:\n- Served over **HTTPS** (valid SSL certificate required)\n- Content-Type: `application/json`\n- Accessible **without redirects** at the exact path `/.well-known/apple-app-site-association`\n- No `.json` extension in the URL\n\n### 4. Add Entitlements\n\nIn your Electron app's entitlements file, add:\n\n```xml\n\u003c!-- Replace with your Team ID and Bundle ID --\u003e\n\u003ckey\u003ecom.apple.application-identifier\u003c/key\u003e\n\u003cstring\u003eTEAM_ID.BUNDLE_ID\u003c/string\u003e\n\u003c!-- Replace example.com with your domain name --\u003e\n\u003ckey\u003ecom.apple.developer.associated-domains\u003c/key\u003e\n\u003carray\u003e\n  \u003cstring\u003ewebcredentials:example.com\u003c/string\u003e\n\u003c/array\u003e\n```\n\n\u003e [!NOTE]\n\u003e The domain in `rpId` must exactly match the domain in your associated domains entitlement and the domain hosting the `apple-app-site-association` file.\n\n### 5. Verification\n\nAfter deployment, you can verify your association file:\n1. Visit `https://example.com/.well-known/apple-app-site-association` in a browser\n2. Use an external validator like [Branch.io AASA Validator](https://branch.io/resources/aasa-validator/) or similar tools\n\n## Provisioning Profile Setup\n\nApps using the `com.apple.developer.associated-domains` entitlement require a **provisioning profile** installed on the development machine. Without it, macOS will reject the app at launch.\n\n**Creating the profile:**\n\n1. Go to [Apple Developer Portal → Identifiers](https://developer.apple.com/account/resources/identifiers/list)\n2. Create or edit an App ID matching your bundle identifier\n3. Enable the **Associated Domains** capability\n4. Go to [Profiles](https://developer.apple.com/account/resources/profiles/list) → create a **macOS App Development** profile for this App ID\n5. Download the `.provisionprofile` file and double-click to install\n\n## API Reference\n\n* [`createCredential(options)`](#create-credential)\n* [`getCredential(options)`](#get-credential)\n* [`managePasswords()`](#manage-passwords)\n\n\u003ca name=\"create-credential\"\u003e\u003c/a\u003e\n\n### `createCredential(options)`\n\nCreates a new passkey credential using Touch ID, iCloud Keychain, or an external security key.\n\n**Options:**\n| Property | Type | Required | Description |\n|----------|------|----------|-------------|\n| `rpId` | string | ✅ | Relying Party identifier (your domain, e.g., \"example.com\") |\n| `userId` | string | ✅ | Stable user identifier (max 64 bytes recommended) |\n| `name` | string | ✅ | User's name (used for both platform and security key authentication) |\n| `displayName` | string | ✅ | User's display name (used for security key only) |\n| `authenticators` | string[] | | Which authenticator types to offer: `['platform', 'securityKey']` (default: both) |\n| `excludeCredentials` | object[] | | Existing credentials to prevent re-registration |\n| `userVerification` | string | | `'required'`, `'preferred'` (default), or `'discouraged'` |\n| `attestation` | string | | `'none'` (default), `'indirect'`, `'direct'`, or `'enterprise'` |\n| `largeBlobRequired` | boolean | | Require largeBlob support (macOS 14.0+, platform keys only) |\n| `prf` | object | | PRF extension request (macOS 15.0+, platform keys only) |\n\n**Returns:** `Promise\u003cRegistrationCredential\u003e`\n\n**Platform credential response** (Touch ID / iCloud Keychain):\n```javascript\n{\n  type: \"platform\",\n  credentialID: string,           // Base64-encoded credential ID\n  attestationObject: string,      // Base64-encoded CBOR attestation\n  clientDataJSON: string,         // Base64-encoded client data\n  attachment?: string,            // \"platform\" or \"crossPlatform\" (macOS 13.5+)\n  largeBlobSupported?: boolean,   // Whether largeBlob is supported (macOS 14.0+)\n  prfEnabled?: boolean,           // Whether PRF extension is supported (macOS 15.0+)\n  prfFirst?: string,              // Base64-encoded first PRF output (if requested)\n  prfSecond?: string              // Base64-encoded second PRF output (if requested)\n}\n```\n\n**Security key credential response** (external FIDO2 key):\n```javascript\n{\n  type: \"securityKey\",\n  credentialID: string,           // Base64-encoded credential ID\n  attestationObject: string,      // Base64-encoded CBOR attestation\n  clientDataJSON: string,         // Base64-encoded client data\n  transports?: string[]           // [\"usb\", \"nfc\", \"ble\", \"internal\", \"hybrid\"] (macOS 14.5+)\n}\n```\n\n---\n\n\u003ca name=\"get-credential\"\u003e\u003c/a\u003e\n\n### `getCredential(options)`\n\nAuthenticates a user using an existing passkey.\n\n**Options:**\n| Property | Type | Required | Description |\n|----------|------|----------|-------------|\n| `rpId` | string | ✅ | Relying Party identifier (your domain) |\n| `authenticators` | string[] | | Which authenticator types to offer: `['platform', 'securityKey']` (default: both) |\n| `allowCredentials` | object[] | | Specific credentials to allow (if not set, discovers available) |\n| `userVerification` | string | | `'required'`, `'preferred'` (default), or `'discouraged'` |\n| `largeBlobOperation` | object | | `{ read: true }` or `{ write: \"base64data\" }` (macOS 14.0+, platform keys only) |\n| `prf` | object | | `{ eval: { first: \"base64\", second?: \"base64\" } }` (macOS 15.0+, platform keys only) |\n\n**Returns:** `Promise\u003cAssertionCredential\u003e`\n\n**Platform credential response** (Touch ID / iCloud Keychain):\n```javascript\n{\n  type: \"platform\",\n  userID: string,                 // Base64-encoded user handle\n  credentialID: string,           // Base64-encoded credential ID\n  authenticatorData: string,      // Base64-encoded authenticator data\n  clientDataJSON: string,         // Base64-encoded client data\n  signature: string,              // Base64-encoded signature\n  attachment?: string,            // \"platform\" or \"crossPlatform\" (macOS 13.5+)\n  largeBlobResult?: object,       // { type: 'read', data } or { type: 'write', success } (macOS 14.0+)\n  prfEnabled?: boolean,           // Whether PRF extension was used (macOS 15.0+)\n  prfFirst?: string,              // Base64-encoded first PRF output\n  prfSecond?: string              // Base64-encoded second PRF output\n}\n```\n\n**Security key credential response** (external FIDO2 key):\n```javascript\n{\n  type: \"securityKey\",\n  userID: string,                 // Base64-encoded user handle\n  credentialID: string,           // Base64-encoded credential ID\n  authenticatorData: string,      // Base64-encoded authenticator data\n  clientDataJSON: string,         // Base64-encoded client data\n  signature: string,              // Base64-encoded signature\n  appID?: boolean                 // Whether legacy FIDO U2F appID was used (macOS 14.5+)\n}\n```\n\n---\n\n\u003ca name=\"manage-passwords\"\u003e\u003c/a\u003e\n\n### `managePasswords()`\n\nOpens the macOS system password manager (_Settings → Passwords_).\n\n**Parameters:** None\n\n**Returns:** `void`\n\n## macOS Platform Quirks\n\n### How It Works\n\nThe addon provides native WebAuthn/Passkey functionality using:\n- **Swift**: Core passkey logic using AuthenticationServices framework (`src/PasskeyManager.swift`)\n- **Objective-C**: Bridge between Swift and C++\n- **C++**: N-API bindings for Node.js integration\n- **JavaScript/TypeScript**: User-friendly wrapper API with full type definitions\n\n\u003e [!NOTE]\n\u003e All credentials use **ES256** algorithm (ECDSA P-256 with SHA-256) — the only algorithm supported by Apple's AuthenticationServices.\n\n### Why is domain association required?\n\nPasskeys are tied to a specific domain (like `example.com`). When you authenticate with a passkey, macOS needs to verify that the app requesting access actually owns that domain — otherwise, a malicious app could impersonate your bank and steal your credentials.\n\nApple enforces this through a two-way trust mechanism:\n1. **Your server proves it trusts the app** — by hosting a file at `https://example.com/.well-known/apple-app-site-association` that lists your app's bundle identifier\n2. **Your app declares which domain it represents** — via the `com.apple.developer.associated-domains` entitlement embedded during code signing\n\nWhen both sides match, macOS allows your app to create and use passkeys for that domain. Without this setup, passkey operations will fail with \"Application is not associated with domain\" errors.\n\n\u003e [!NOTE]\n\u003e In browsers, `localhost` is exempt from domain verification for development convenience. Native macOS code has no such exception — domain association is always required, even for local testing. You'll need a real domain with HTTPS to develop and test passkey functionality with this addon.\n\n### Platform vs Security Key authenticators\n\nApple's AuthenticationServices framework distinguishes between two authenticator types (see [Apple's documentation](https://developer.apple.com/documentation/authenticationservices/public-private-key-authentication)):\n\n| Type | What it is | Examples |\n|------|------------|----------|\n| **Platform** | Built-in or tightly integrated with the device | Touch ID, Face ID, iCloud Keychain, cross-device via QR code |\n| **Security Key** | External FIDO2 hardware tokens | YubiKey, Titan Key, etc (via USB, NFC, or Bluetooth) |\n\nAs of 2025, PRF and LargeBlob extensions are only available for **platform** authenticators.\n\n### Differences from Browser WebAuthn\n\nThis addon differs from the standard browser-based Web Authentication API (`navigator.credentials`) due to Apple's `AuthenticationServices` framework limitations:\n\n| Parameter | Browser WebAuthn | This Addon |\n|-----------|------------------|------------|\n| `challenge` | Server-generated, passed to API | Auto-generated internally (32 bytes via `SecRandomCopyBytes`). Retrieve from `clientDataJSON` if needed. |\n| `rp.name` | Human-readable RP name shown to user | Not supported — macOS shows `rpId` domain instead |\n| `timeout` | Configurable operation timeout | Not supported — system manages timeouts internally |\n| `pubKeyCredParams` | Multiple algorithms supported | ES256 only (hardcoded by Apple) |\n| PRF, LargeBlob | Available on all authenticators | Platform authenticators only — see [Platform vs Security Key](#platform-vs-security-key-authenticators) |\n\n## Troubleshooting\n\n### \"The calling process does not have an application identifier. Make sure it is properly configured.\"\n\nThe app is not running as a signed `.app` bundle. Follow [Sign and run the app](#4-sign-and-run-the-app) to build and code-sign your application.\n\n### \"Application is not associated with domain\" or \"No credentials available\"\n\nThe `rpId` domain is not associated with your app. Follow [Configuring Entitlements and Domain Association](#configuring-entitlements-and-domain-association) and verify that your Team ID and Bundle ID match in both the server-hosted file and your app's entitlements.\n\n### App builds but shows \"could not be opened\" alert on launch\n\nYour app uses restricted entitlements (`associated-domains`) but no matching provisioning profile is installed. macOS blocks such apps with a generic \"could not be opened\" dialog (system logs show \"No matching profile found\"). Follow [Provisioning Profile Setup](#provisioning-profile-setup) to create and install a development profile for your bundle ID.\n\n### PRF or LargeBlob extensions are not working\n\nThese extensions are only supported for platform authenticators (Touch ID / iCloud Keychain), not security keys. Use `authenticators: ['platform']` to restrict to platform keys when using these extensions.\n\n## Plugin Development\n\n### Prerequisites\n\n- macOS 13.0+ (Ventura or later)\n- Xcode 15+ with Command Line Tools (`xcode-select --install`)\n- Node.js 18+ with npm\n- Apple Developer account (for code signing)\n\n### Project Structure\n\n```\nelectron-webauthn-mac/\n├── src/                       # Swift/Objective-C/C++ source code\n│   └── PasskeyManager.swift   # Core WebAuthn logic (used by addon and dev app)\n├── js/                        # JavaScript wrapper + TypeScript definitions\n├── include/                   # Header file\n├── native/                    # Prebuilt .node binary (generated)\n├── binding.gyp                # node-gyp build configuration\n├── example-electron-app/      # Example Electron application\n└── dev-mac-app/               # Native macOS dev app (Xcode project)\n```\n\n### Building the Addon\n\n```bash\nnpm install\nnpm run build\n```\n\nThis compiles the Swift code, builds the native addon, and copies the `.node` binary to `native/`.\n\n### WebAuthn Playground (Development App)\n\nFor faster iteration during development, use the native macOS dev app:\n\n```bash\nopen dev-mac-app/WebAuthnPlayground.xcodeproj\n# Build and run in Xcode (⌘R)\n```\n\n**Why a separate native app?**\n\nBuilding through Electron requires code signing and bundling — which is slow. The native app provides:\n\n- **Instant iteration** — build and run directly from Xcode in seconds\n- **Full debugger access** — set breakpoints in Swift code, inspect variables\n- **API playground** — quickly test new AuthenticationServices features\n- **Shared codebase** — both Electron example and Playground projects use the same `PasskeyManager.swift` from `src/`\n\nThe playground includes buttons for all WebAuthn operations: registration, authentication, PRF encryption/decryption, and largeBlob read/write.\n\n\u003e [!TIP]\n\u003e When developing new features, prototype them in the playground first, then integrate into the Electron addon once verified.\n\n### Publishing\n\n```bash\nnpm run build        # Builds and copies .node to native/\nnpm publish          # prepublishOnly runs build automatically\n```\n\n## License\n\nThis project is released under the [MIT License](http://opensource.org/licenses/MIT).\n\n---\n\n\u003cp align=\"center\"\u003e\n  Made with ❤️ by the \u003ca href=\"https://github.com/vault12\"\u003eVault12 Team\u003c/a\u003e\n\u003c/p\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvault12%2Felectron-webauthn-mac","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvault12%2Felectron-webauthn-mac","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvault12%2Felectron-webauthn-mac/lists"}