{"_id":"@defiob/wallet-plugin-passkey","name":"@defiob/wallet-plugin-passkey","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@defiob/wallet-plugin-passkey","description":"A WharfKit wallet plugin that signs Antelope transactions with a WebAuthn passkey (PUB_WA_).","version":"0.1.0","license":"BSD-3-Clause","homepage":"https://github.com/defiob/wallet-plugin-passkey","repository":{"type":"git","url":"git+https://github.com/defiob/wallet-plugin-passkey.git"},"bugs":{"url":"https://github.com/defiob/wallet-plugin-passkey/issues"},"publishConfig":{"access":"public"},"type":"module","module":"lib/wallet-plugin-passkey.mjs","types":"lib/wallet-plugin-passkey.d.ts","sideEffects":false,"exports":{".":{"types":"./lib/wallet-plugin-passkey.d.ts","import":"./lib/wallet-plugin-passkey.mjs"}},"peerDependencies":{"@wharfkit/session":"^1.6.0"},"dependencies":{"@noble/curves":"^1.6.0","@noble/hashes":"^2.2.0","@wharfkit/antelope":"^1.2.0","bs58":"^6.0.0"},"devDependencies":{"@wharfkit/session":"^1.6.0","tsup":"^8.5.0","typescript":"^5.7.3"},"scripts":{"build":"tsup","dev":"tsup --watch","typecheck":"tsc --noEmit"},"_id":"@defiob/wallet-plugin-passkey@0.1.0","_integrity":"sha512-aRkTPcG+NySCcK+pkQCQd/N+ynoA43p0lrl5AtnCdXRg4ux8zd2yrj7sGtCt64sYrsVxoKZJjlRMnhxsbrU2Nw==","_resolved":"/tmp/adfafe6d2de87c705a3d1f4db822e35f/defiob-wallet-plugin-passkey-0.1.0.tgz","_from":"file:defiob-wallet-plugin-passkey-0.1.0.tgz","_nodeVersion":"24.15.0","_npmVersion":"11.12.1","dist":{"integrity":"sha512-aRkTPcG+NySCcK+pkQCQd/N+ynoA43p0lrl5AtnCdXRg4ux8zd2yrj7sGtCt64sYrsVxoKZJjlRMnhxsbrU2Nw==","shasum":"c0a3b65d75b9ed86cadf6c7bce4f96af9cabc075","tarball":"https://registry.npmjs.org/@defiob/wallet-plugin-passkey/-/wallet-plugin-passkey-0.1.0.tgz","fileCount":15,"unpackedSize":82608,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@defiob%2fwallet-plugin-passkey@0.1.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIAqIND9HNATP075bPCXRZi6cH3V7lXVd5x3cSM1bYCLKAiBNqQSrskOisKH9Vtkqry4l/dYSpfK+ISd13CqpD8O5Sg=="}]},"_npmUser":{"name":"defiob","email":"defiob22@gmail.com"},"directories":{},"maintainers":[{"name":"defiob","email":"defiob22@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/wallet-plugin-passkey_0.1.0_1779324456819_0.2640628638222937"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-21T00:47:36.397Z","0.1.0":"2026-05-21T00:47:36.951Z","modified":"2026-05-21T00:47:37.500Z"},"maintainers":[{"name":"defiob","email":"defiob22@gmail.com"}],"description":"A WharfKit wallet plugin that signs Antelope transactions with a WebAuthn passkey (PUB_WA_).","homepage":"https://github.com/defiob/wallet-plugin-passkey","repository":{"type":"git","url":"git+https://github.com/defiob/wallet-plugin-passkey.git"},"bugs":{"url":"https://github.com/defiob/wallet-plugin-passkey/issues"},"license":"BSD-3-Clause","readme":"# @defiob/wallet-plugin-passkey\n\nA [WharfKit](https://wharfkit.com) wallet plugin that signs Antelope\n(EOS / Vaulta / Telos / WAX / Jungle / …) transactions with a **WebAuthn\npasskey** —  a `PUB_WA_…` public key registered in the user's on-chain\npermission authority.\n\n- **No private keys to back up.** The signing material is whatever the\n  user's device already gates with their biometric (Touch ID, Windows\n  Hello, security key, phone passkey via QR).\n- **No backend account database.** Login uses ECDSA public-key recovery\n  + a single reverse-lookup call to find which account the passkey\n  belongs to. The user picks \"Passkey\" in the wallet picker, taps their\n  fingerprint, and they're in.\n- **Plain WharfKit citizen.** Drop it into `SessionKit({ walletPlugins })`\n  and every `session.transact(...)` call automatically supports passkey\n  signing. No changes to dApp panels.\n\n## Install\n\n```bash\npnpm add @defiob/wallet-plugin-passkey\n# or: npm install @defiob/wallet-plugin-passkey\n```\n\nPeer dep: `@wharfkit/session ^1.6.0`.\n\n## Usage\n\n```ts\nimport { SessionKit } from '@wharfkit/session'\nimport { WebRenderer } from '@wharfkit/web-renderer'\nimport { WalletPluginPasskey } from '@defiob/wallet-plugin-passkey'\n\nconst kit = new SessionKit({\n  appName: 'myapp',\n  chains: [{ id: '...', url: 'https://...' }],\n  ui: new WebRenderer(),\n  walletPlugins: [\n    new WalletPluginPasskey(),\n    // ...your other wallet plugins\n  ],\n})\n```\n\n### Options\n\n```ts\nnew WalletPluginPasskey({\n  /**\n   * Reverse-lookup endpoint base URL. The plugin appends the candidate\n   * PUB_WA_ string directly. Must respond with JSON of shape:\n   *   { accounts: [{account, permission}], pubkey, recursive }\n   *\n   * Default: 'https://state.eoseyes.com/v2/key/'\n   */\n  reverseLookupUrl: 'https://your.lookup.host/v2/key/',\n})\n```\n\nIf you operate your own chain or want to point at a different aggregator,\noverride `reverseLookupUrl`. Empty `accounts` is treated as \"not bound on\nchain\".\n\n## Registering a passkey before first use\n\nA passkey only becomes usable once its `PUB_WA_…` is added to a permission\non chain. This plugin **signs with** an existing passkey; it doesn't add\nnew ones. The flow is typically:\n\n1. User connects to the dApp with their existing wallet (Anchor, Metahub,\n   …).\n2. dApp lets them create a passkey via `navigator.credentials.create()`\n   and derives the corresponding `PUB_WA_…`.\n3. dApp builds an `eosio::updateauth` action adding that key to their\n   permission, signed by their existing wallet.\n4. Once on chain, this plugin's login() can find it.\n\nFor a reference implementation of step 2–3 see the EOSEyes\n`/wallet → Permissions` panel.\n\n## How it works\n\n### Login\n\nWebAuthn's `navigator.credentials.get()` returns a signature but not the\npublic key. To find the public key without asking the user to type an\naccount name, the plugin runs ECDSA recovery and a reverse lookup:\n\n1. Browser prompts the user to pick a passkey on the device (random\n   challenge, no `allowCredentials` filter).\n2. Parse the assertion's DER signature into raw `(r, s)`; build the\n   signing input `authData || sha256(clientDataJSON)`.\n3. ECDSA recovery yields **two candidate** P-256 public keys.\n4. For each candidate, encode the canonical `PUB_WA_…` string (compressed\n   point + UP/UV byte from authData flags + current `rpId`), then call\n   `reverseLookupUrl`.\n5. The candidate whose `PUB_WA_…` returns non-empty `accounts` is the\n   real public key.\n6. If exactly one account → auto-bind. If multiple → prefer `@active`,\n   fall back to the first.\n7. Persist `credentialID` + `publicKey` + `permissionLevel` so subsequent\n   `sign()` calls don't need another lookup.\n\n### Sign\n\n1. Build the Antelope transaction's signing digest:\n   `Transaction.signingDigest(chainId)`.\n2. WebAuthn `navigator.credentials.get()` with that 32-byte digest as the\n   challenge and the stored `credentialID` in `allowCredentials`.\n3. Parse the DER signature, recover the recid by matching candidates\n   against the stored public key, low-S normalise (`s = n - s; recid ^=\n   1` when `s > n/2`).\n4. Assemble the on-chain WA Signature bytes:\n\n   ```\n   recid + 31              (1 byte)\n   r                       (32 bytes, big-endian)\n   s                       (32 bytes, big-endian)\n   varuint32(authData.len) | authData\n   varuint32(cdj.len)      | clientDataJSON\n   ```\n\n5. Return `{ signatures: [Signature(KeyType.WA, bytes)] }`.\n\n## Caveats\n\n- **Secure context required.** Browsers only allow WebAuthn over\n  `https://*` and `http://localhost`. Raw IP literals (including\n  `127.0.0.1`) are rejected by browsers, and Antelope's chain-side\n  verifier additionally requires `clientDataJSON.origin` to begin with\n  `https://` — so even `http://localhost` will fail when the signature\n  reaches the chain. For local development, run your dev server on\n  `https://localhost` (e.g. `next dev --experimental-https`).\n- **`PUB_WA_…` is origin-scoped.** The string embeds the `rpId` (current\n  hostname). A passkey registered at `example.com` produces a different\n  `PUB_WA_…` than the same key would at `example.org`. Passkeys created\n  on different origins are not interchangeable on chain.\n- **Login UI for multi-account passkeys is minimal.** If the same passkey\n  is registered on more than one `(account, permission)`, this plugin\n  currently picks the `@active` permission or the first match and\n  surfaces a `context.ui.status()` message. A first-class picker waits on\n  WharfKit's UserInterface protocol gaining a structured choice prompt.\n\n## Build\n\n```bash\npnpm install\npnpm build        # → lib/wallet-plugin-passkey.{js,mjs,d.ts}\npnpm typecheck\n```\n\nBuild tool: [tsup](https://tsup.egoist.dev). Output formats: CJS + ESM,\nmatching the layout of official `@wharfkit/wallet-plugin-*` packages.\n\n## License\n\nBSD-3-Clause. © 2026 defiob.\n","readmeFilename":"README.md","_rev":"1-d0994d63c6ce99cdeaaa6bcd5eccbc1e"}