npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@cognitiveproof/webauthn-prf-identity

v0.3.0

Published

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.

Readme

@cognitiveproof/webauthn-prf-identity

Derives a per-profile Ed25519 identity key in the browser from a WebAuthn credential's PRF (pseudo-random function) extension output, and computes the did:jwk issuer identifier expected by c2pa-rs-javascript-library's ICA (Identity Claims Aggregation) signing path.

The raw Ed25519 seed never leaves the browser and is never persisted — it's re-derived fresh from the authenticator each time a profile needs to sign something (PRF output for a given credential + salt is deterministic). Only the credential id, the (non-secret) salt, and the resulting DID are ever sent anywhere else.

Ships with a "use client" directive so it can be imported directly into Next.js App Router client components without consumers needing to add the pragma themselves.

Install

npm install @cognitiveproof/webauthn-prf-identity

Requires a browser with WebAuthn PRF extension support (e.g. Chrome/Edge with a platform authenticator, or a PRF-capable security key).

Usage

Every function that touches key material takes a WebAuthnPrfIdentityConfig — set hkdfInfo to something unique to your application. It's the HKDF domain-separation label between the raw PRF output and the derived Ed25519 seed, so two applications that shared a label (and somehow shared a credential + salt pair) would derive the same key.

import {
    isWebAuthnSupported,
    registerWebAuthnPrfCredential,
    deriveSigningSeed,
    signBytes,
    computeIcaIssuerDidFromPublicKey,
    PrfNotSupportedError,
} from "@cognitiveproof/webauthn-prf-identity";

const config = {
    rpName: "My App",
    hkdfInfo: "my-app-ica-v1",
};

// Once per profile, during onboarding:
if (isWebAuthnSupported()) {
    try {
        const { credentialId, prfSalt, publicKey, issuerDid } =
            await registerWebAuthnPrfCredential(config, profileId, displayName);
        // Persist credentialId, prfSalt, publicKey, and issuerDid server-side.
        // The Ed25519 seed itself is never returned or stored.
    } catch (err) {
        if (err instanceof PrfNotSupportedError) {
            // Fall back to whatever non-client-side signing path your app uses.
        }
    }
}

// Later, at signing time (credential = { credentialId, prfSalt } loaded back
// from wherever you persisted it above):
const signature = await signBytes(config, credential, toSign);

API

  • isWebAuthnSupported(): boolean — whether the browser exposes the WebAuthn API at all. Whether the specific authenticator supports the PRF extension is only known after attempting registration.
  • registerWebAuthnPrfCredential(config, profileId, profileDisplayName): Promise<WebAuthnRegistrationResult> — registers a new credential and returns { credentialId, prfSalt, publicKey, issuerDid }. publicKey is the base64url-encoded raw 32-byte Ed25519 public key, given directly so you don't have to decode it back out of issuerDid. On most authenticators this fires two native WebAuthn prompts back to back (one to create the credential, one to evaluate PRF — see beginWebAuthnPrfRegistration below for why) with no app UI in between. If you want to explain the second prompt to the user first, call the two steps yourself instead of this all-in-one convenience wrapper.
  • beginWebAuthnPrfRegistration(config, profileId, profileDisplayName): Promise<{ credentialId: string }> — step 1 of registration: creates the WebAuthn credential (first native prompt) and confirms the authenticator supports PRF. Doesn't evaluate PRF yet, so it doesn't return key material.
  • finishWebAuthnPrfRegistration(config, credentialId): Promise<WebAuthnRegistrationResult> — step 2: evaluates PRF for the credential beginWebAuthnPrfRegistration just created (second native prompt — most authenticators can't return a usable PRF secret during creation itself, only on a follow-up assertion) and derives the Ed25519 key and DID from it. Call this only after beginWebAuthnPrfRegistration has resolved for the same credential.
  • deriveSigningSeed(config, credential): Promise<Uint8Array> — re-derives the raw 32-byte Ed25519 seed for an already-registered credential. Prompts the authenticator; that prompt is the user's consent.
  • signBytes(config, credential, toSign): Promise<Uint8Array> — signs arbitrary bytes with the profile's device-derived key and returns a 64-byte raw (RFC 8032, R||S) signature.
  • signIcaToSign(config, credential, toSign): Promise<Uint8Array> — alias for signBytes, named for c2pa-rs-javascript-library's ICA (Identity Claims Aggregation) signing path: signs bytes from manifest.prepareIcaSigning and returns what manifest.finalizeIcaSigning expects.
  • computeIcaIssuerDidFromPublicKey(publicKey): string — did:jwk encoding for an Ed25519 public key, matching c2pa-rs-javascript-library's own computeIcaIssuerDid(). Pure function, no config needed.
  • PrfNotSupportedError — thrown when the authenticator/browser combination doesn't support the PRF extension.

Development

npm install
npm run build       # tsup -> dist/{index.js,index.cjs,index.d.ts}
npm run typecheck
npm run playground  # builds, then serves playground/index.html for manual testing

playground/ is a manual test page for exercising real WebAuthn prompts in a real browser (this can't be automated headlessly) — it's excluded from the published package via package.json's files field.