{"_id":"@cognitiveproof/webauthn-prf-identity","_rev":"3-4d30a6686259894b85e66cad72a48a1e","name":"@cognitiveproof/webauthn-prf-identity","dist-tags":{"latest":"0.3.0"},"versions":{"0.1.0":{"name":"@cognitiveproof/webauthn-prf-identity","version":"0.1.0","keywords":["webauthn","prf","ed25519","did","c2pa"],"license":"MIT","_id":"@cognitiveproof/webauthn-prf-identity@0.1.0","maintainers":[{"name":"mrappard","email":"mrappard@gmail.com"}],"dist":{"shasum":"d5fd433af0888111eefdea99313208ae76360f11","tarball":"https://registry.npmjs.org/@cognitiveproof/webauthn-prf-identity/-/webauthn-prf-identity-0.1.0.tgz","fileCount":9,"integrity":"sha512-wfcVtuVw+Aup0wCK0Et8bdTbiDLCNWPThZEA/Skk+owhAt/lZsrRYWOkQ1VKNUC2c/1Ni+/NwyzK+tHt798XGg==","signatures":[{"sig":"MEUCIDvoozWdfxXjU7s1L918UNCG7ct/OP4Una3xwtDSPmN2AiEAwGdQL6DR2vpe1oNTZT+6JBiVmPQGeIAqVU1Dz8v46I0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":51540},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"scripts":{"dev":"tsup --watch","build":"tsup","typecheck":"tsc --noEmit","playground":"npm run build && node playground/serve.mjs","prepublishOnly":"npm run typecheck && npm run build"},"_npmUser":{"name":"mrappard","email":"mrappard@gmail.com"},"_npmVersion":"11.12.1","description":"Derive a per-profile Ed25519 identity key in the browser from a WebAuthn PRF extension output, and compute the did:jwk issuer identifier expected by c2pa-rs-javascript-library's ICA signing path.","directories":{},"sideEffects":false,"_nodeVersion":"25.9.0","dependencies":{"@noble/curves":"^1.6.0","@noble/hashes":"^1.5.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.0","typescript":"^5.6.0"},"_npmOperationalInternal":{"tmp":"tmp/webauthn-prf-identity_0.1.0_1787883911937_0.43079556087101434","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@cognitiveproof/webauthn-prf-identity","version":"0.2.0","keywords":["webauthn","prf","ed25519","did","c2pa"],"license":"MIT","_id":"@cognitiveproof/webauthn-prf-identity@0.2.0","maintainers":[{"name":"mrappard","email":"mrappard@gmail.com"}],"dist":{"shasum":"b2706c2a4aa273eb79274aa8959553a9c214a8ae","tarball":"https://registry.npmjs.org/@cognitiveproof/webauthn-prf-identity/-/webauthn-prf-identity-0.2.0.tgz","fileCount":9,"integrity":"sha512-AcjxFmVtU0bBeB7+MwcgGyoeyBXxiLYzUm2k5J3gVQrJv9lPvtTFCkk2GOZBxSTU8cK0EE5IrV9pdQhHjZ/Eng==","signatures":[{"sig":"MEUCICef7ANWuvqBOgahbS3jP4o68OqlctUZcZms1M29+9EjAiEAk2RBXKbTKwD42n++d7CkbNFwXwA3AOfWCrGL6eid3y4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":54591},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"gitHead":"11bb2858f3ad8d9817c763757edc7208f617808a","scripts":{"dev":"tsup --watch","build":"tsup","typecheck":"tsc --noEmit","playground":"npm run build && node playground/serve.mjs","prepublishOnly":"npm run typecheck && npm run build"},"_npmUser":{"name":"mrappard","email":"mrappard@gmail.com"},"_npmVersion":"11.12.1","description":"Derive a per-profile Ed25519 identity key in the browser from a WebAuthn PRF extension output, and compute the did:jwk issuer identifier expected by c2pa-rs-javascript-library's ICA signing path.","directories":{},"sideEffects":false,"_nodeVersion":"25.9.0","dependencies":{"@noble/curves":"^1.6.0","@noble/hashes":"^1.5.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.0","typescript":"^5.6.0"},"_npmOperationalInternal":{"tmp":"tmp/webauthn-prf-identity_0.2.0_1787884823160_0.034439782305397904","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@cognitiveproof/webauthn-prf-identity","version":"0.3.0","description":"Derive a per-profile Ed25519 identity key in the browser from a WebAuthn PRF extension output, and compute the did:jwk issuer identifier expected by c2pa-rs-javascript-library's ICA signing path.","type":"module","main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"sideEffects":false,"publishConfig":{"access":"public"},"scripts":{"build":"tsup","dev":"tsup --watch","typecheck":"tsc --noEmit","playground":"npm run build && node playground/serve.mjs","prepublishOnly":"npm run typecheck && npm run build"},"dependencies":{"@noble/curves":"^1.6.0","@noble/hashes":"^1.5.0"},"devDependencies":{"tsup":"^8.3.0","typescript":"^5.6.0"},"keywords":["webauthn","prf","ed25519","did","c2pa"],"engines":{"node":">=18"},"license":"MIT","gitHead":"5d78498f46bbfab70c7691c36a074d44c046be03","_id":"@cognitiveproof/webauthn-prf-identity@0.3.0","_nodeVersion":"25.9.0","_npmVersion":"11.12.1","dist":{"integrity":"sha512-+wXWzzj/CE+3QEhnVKOk0mgnYO+pFlsE2dI6ctSVlOCS9qNtTDBdYkg8JvjlpiZbwXCIsVRA8PmJnKgH/xhYaw==","shasum":"ffb18dad4c44bbf3cdfe0f9e0835e1a3d60b05f0","tarball":"https://registry.npmjs.org/@cognitiveproof/webauthn-prf-identity/-/webauthn-prf-identity-0.3.0.tgz","fileCount":9,"unpackedSize":64410,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIC2pYO7aCmA0eI6hulN5W/DB/IEvWUxA3NCh0N7P6lVkAiB7ELLG58BP7poqp+C6N6S6GOyDlzlJ3Jr6I4M1KVTezg=="}]},"_npmUser":{"name":"mrappard","email":"mrappard@gmail.com"},"directories":{},"maintainers":[{"name":"mrappard","email":"mrappard@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/webauthn-prf-identity_0.3.0_1788200609001_0.4017022264481802"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-28T02:25:11.794Z","modified":"2026-08-31T18:23:29.381Z","0.1.0":"2026-08-28T02:25:12.099Z","0.2.0":"2026-08-28T02:40:23.316Z","0.3.0":"2026-08-31T18:23:29.144Z"},"license":"MIT","keywords":["webauthn","prf","ed25519","did","c2pa"],"description":"Derive a per-profile Ed25519 identity key in the browser from a WebAuthn PRF extension output, and compute the did:jwk issuer identifier expected by c2pa-rs-javascript-library's ICA signing path.","maintainers":[{"name":"mrappard","email":"mrappard@gmail.com"}],"readme":"# @cognitiveproof/webauthn-prf-identity\n\nDerives a per-profile Ed25519 identity key in the browser from a WebAuthn\ncredential's PRF (pseudo-random function) extension output, and computes the\n`did:jwk` issuer identifier expected by\n[c2pa-rs-javascript-library](https://github.com/contentauth/c2pa-rs)'s ICA\n(Identity Claims Aggregation) signing path.\n\nThe raw Ed25519 seed never leaves the browser and is never persisted — it's\nre-derived fresh from the authenticator each time a profile needs to sign\nsomething (PRF output for a given credential + salt is deterministic). Only\nthe credential id, the (non-secret) salt, and the resulting DID are ever\nsent anywhere else.\n\nShips with a `\"use client\"` directive so it can be imported directly into\nNext.js App Router client components without consumers needing to add the\npragma themselves.\n\n## Install\n\n```sh\nnpm install @cognitiveproof/webauthn-prf-identity\n```\n\nRequires a browser with WebAuthn PRF extension support (e.g. Chrome/Edge\nwith a platform authenticator, or a PRF-capable security key).\n\n## Usage\n\nEvery function that touches key material takes a `WebAuthnPrfIdentityConfig`\n— set `hkdfInfo` to something unique to your application. It's the HKDF\ndomain-separation label between the raw PRF output and the derived Ed25519\nseed, so two applications that shared a label (and somehow shared a\ncredential + salt pair) would derive the same key.\n\n```ts\nimport {\n    isWebAuthnSupported,\n    registerWebAuthnPrfCredential,\n    deriveSigningSeed,\n    signBytes,\n    computeIcaIssuerDidFromPublicKey,\n    PrfNotSupportedError,\n} from \"@cognitiveproof/webauthn-prf-identity\";\n\nconst config = {\n    rpName: \"My App\",\n    hkdfInfo: \"my-app-ica-v1\",\n};\n\n// Once per profile, during onboarding:\nif (isWebAuthnSupported()) {\n    try {\n        const { credentialId, prfSalt, publicKey, issuerDid } =\n            await registerWebAuthnPrfCredential(config, profileId, displayName);\n        // Persist credentialId, prfSalt, publicKey, and issuerDid server-side.\n        // The Ed25519 seed itself is never returned or stored.\n    } catch (err) {\n        if (err instanceof PrfNotSupportedError) {\n            // Fall back to whatever non-client-side signing path your app uses.\n        }\n    }\n}\n\n// Later, at signing time (credential = { credentialId, prfSalt } loaded back\n// from wherever you persisted it above):\nconst signature = await signBytes(config, credential, toSign);\n```\n\n## API\n\n- `isWebAuthnSupported(): boolean` — whether the browser exposes the\n  WebAuthn API at all. Whether the specific authenticator supports the PRF\n  extension is only known after attempting registration.\n- `registerWebAuthnPrfCredential(config, profileId, profileDisplayName): Promise<WebAuthnRegistrationResult>`\n  — registers a new credential and returns `{ credentialId, prfSalt, publicKey, issuerDid }`.\n  `publicKey` is the base64url-encoded raw 32-byte Ed25519 public key, given\n  directly so you don't have to decode it back out of `issuerDid`. On most\n  authenticators this fires **two** native WebAuthn prompts back to back\n  (one to create the credential, one to evaluate PRF — see\n  `beginWebAuthnPrfRegistration` below for why) with no app UI in between.\n  If you want to explain the second prompt to the user first, call the two\n  steps yourself instead of this all-in-one convenience wrapper.\n- `beginWebAuthnPrfRegistration(config, profileId, profileDisplayName): Promise<{ credentialId: string }>`\n  — step 1 of registration: creates the WebAuthn credential (first native\n  prompt) and confirms the authenticator supports PRF. Doesn't evaluate PRF\n  yet, so it doesn't return key material.\n- `finishWebAuthnPrfRegistration(config, credentialId): Promise<WebAuthnRegistrationResult>`\n  — step 2: evaluates PRF for the credential `beginWebAuthnPrfRegistration`\n  just created (second native prompt — most authenticators can't return a\n  usable PRF secret during creation itself, only on a follow-up assertion)\n  and derives the Ed25519 key and DID from it. Call this only after\n  `beginWebAuthnPrfRegistration` has resolved for the same credential.\n- `deriveSigningSeed(config, credential): Promise<Uint8Array>` — re-derives\n  the raw 32-byte Ed25519 seed for an already-registered credential. Prompts\n  the authenticator; that prompt is the user's consent.\n- `signBytes(config, credential, toSign): Promise<Uint8Array>` — signs\n  arbitrary bytes with the profile's device-derived key and returns a\n  64-byte raw (RFC 8032, R||S) signature.\n- `signIcaToSign(config, credential, toSign): Promise<Uint8Array>` — alias\n  for `signBytes`, named for c2pa-rs-javascript-library's ICA (Identity\n  Claims Aggregation) signing path: signs bytes from\n  `manifest.prepareIcaSigning` and returns what\n  `manifest.finalizeIcaSigning` expects.\n- `computeIcaIssuerDidFromPublicKey(publicKey): string` — `did:jwk` encoding\n  for an Ed25519 public key, matching c2pa-rs-javascript-library's own\n  `computeIcaIssuerDid()`. Pure function, no config needed.\n- `PrfNotSupportedError` — thrown when the authenticator/browser\n  combination doesn't support the PRF extension.\n\n## Development\n\n```sh\nnpm install\nnpm run build       # tsup -> dist/{index.js,index.cjs,index.d.ts}\nnpm run typecheck\nnpm run playground  # builds, then serves playground/index.html for manual testing\n```\n\n`playground/` is a manual test page for exercising real WebAuthn prompts in\na real browser (this can't be automated headlessly) — it's excluded from the\npublished package via `package.json`'s `files` field.\n","readmeFilename":"README.md"}