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

@le-space/orbitdb-identity-provider-webauthn-did

v0.2.13

Published

WebAuthn-based DID identity provider for OrbitDB for hardware-secured wallets and biometric Passkey authentication

Readme

OrbitDB WebAuthn Identity Providers

CI

⚠️ Security: Experimental release. No formal audit. Use only after your own review.

This package provides:

  • Two WebAuthn-based OrbitDB identity providers.
  • A standalone WebAuthn toolkit export (@le-space/orbitdb-identity-provider-webauthn-did/standalone) for reuse outside OrbitDB identity wiring.
  • WebAuthn-Varsig: No insecure OrbitDB keystore at all. Each entry is signed by WebAuthn (varsig envelope), so keys never leave the authenticator, one Passkey (WebAuthn) prompt per write.
  • Keystore-based DID: Generates an Ed25519/secp256k1 keystore keypair for OrbitDB signing in browser memory. When encryptKeystore is enabled, the private key is encrypted with AES-GCM and only rehydrated in memory after a WebAuthn unlock (PRF, largeBlob, or hmac-secret).

Current WebAuthn Model

  • Discoverable credentials are enabled by default across the shared WebAuthn config.
  • Authentication/assertion requests omit allowCredentials by default, so the browser/authenticator can resolve the credential discoverably.
  • You can switch this centrally with configureWebAuthn({ discoverableCredentials: true|false }).
  • Registration is still the point where this package extracts the credential public key from attestation.
  • Later navigator.credentials.get() assertions do not reliably return the public key again, so identity reconstruction still needs metadata from somewhere else.

In this repo today, metadata recovery works in two layers:

  • Preferred recovery path: store identity metadata in WebAuthn largeBlob and recover it later through discoverable authentication.
  • Fallback recovery path: store the same metadata in browser localStorage.

This means discoverable credentials remove the need to pre-select the credential for authentication, but they do not by themselves eliminate the need for identity metadata persistence.

Recommendation (security-first):

  • Best security: Varsig provider (hardware-backed key for every write).
  • Best balance: Keystore provider with WebAuthn-encrypted keystore (fewer prompts, faster writes, key material in memory during session).

Note: WebAuthn varsig support in this repo relies on our forked @le-space/iso-* packages of Hugo Dias iso-repo (notably @le-space/iso-did and @le-space/iso-webauthn-varsig) to align with the updated varsig flow.

Install

npm install @le-space/orbitdb-identity-provider-webauthn-did

Note: @orbitdb/core is patched (via patch-package) to support Ed25519 keystore keys.

WebAuthn Configuration

The package now exposes a central WebAuthn policy API:

import {
  configureWebAuthn,
  getWebAuthnConfig,
  resetWebAuthnConfig,
} from '@le-space/orbitdb-identity-provider-webauthn-did';

configureWebAuthn({ discoverableCredentials: true }); // default
console.log(getWebAuthnConfig());
resetWebAuthnConfig();

Behavior:

  • discoverableCredentials: true
    • registration requests resident/discoverable credentials
    • assertion requests omit allowCredentials
  • discoverableCredentials: false
    • assertion requests target a specific credential ID via allowCredentials

Memory Keystore Quick Start

import {
  WebAuthnDIDProvider,
  OrbitDBWebAuthnIdentityProviderFunction,
} from '@le-space/orbitdb-identity-provider-webauthn-did';

const credential = await WebAuthnDIDProvider.createCredential({
  userId: '[email protected]',
  displayName: 'Alice',
});

const identity = await identities.createIdentity({
  provider: OrbitDBWebAuthnIdentityProviderFunction({
    webauthnCredential: credential,
  }),
});

Discoverable Recovery Notes

For the DID-based flow:

  • createCredential() can extract the public key from attestation and derive a DID from it.
  • later discoverable navigator.credentials.get() proves possession of the credential, but usually returns only rawId, authenticatorData, clientDataJSON, signature, and maybe userHandle
  • that assertion is not enough on its own to reconstruct the DID

To address this, the demos now attempt to:

  1. write identity metadata to largeBlob after passkey creation
  2. recover that metadata later through discoverable authentication
  3. fall back to local browser storage if largeBlob is unavailable or empty

Hardware-Secured Varsig Quick Start

import {
  WebAuthnVarsigProvider,
  createWebAuthnVarsigIdentity,
} from '@le-space/orbitdb-identity-provider-webauthn-did';

const credential = await WebAuthnVarsigProvider.createCredential({
  userId: '[email protected]',
  displayName: 'Alice',
});

const identity = await createWebAuthnVarsigIdentity({ credential });

For varsig, the same recovery limitation applies: a discoverable assertion identifies the credential but does not re-export the public key. The demos therefore use the same largeBlob-first, local fallback recovery approach for varsig credential metadata.

Standalone Toolkit (without OrbitDB identity provider wiring)

Use the standalone export when you want WebAuthn signer and worker-keystore features independently from OrbitDB identity provider setup.

import {
  createWebAuthnSigner,
  WebAuthnHardwareSignerService,
  createWorkerKeystoreClient,
} from '@le-space/orbitdb-identity-provider-webauthn-did/standalone';

// Create a hardware-backed WebAuthn varsig signer
const signer = await createWebAuthnSigner({
  userId: '[email protected]',
  displayName: 'Alice',
});

// Optional: bridge to UCAN signer surface
const ucantoSigner = signer.toUcantoSigner();

// Optional: persisted hardware signer lifecycle
const hardwareService = new WebAuthnHardwareSignerService();
await hardwareService.initialize({
  userId: '[email protected]',
  displayName: 'Alice',
});

// Optional: worker-based Ed25519 keystore client
const workerClient = createWorkerKeystoreClient();

Domain Label Guidance (OrbitDB vs UCAN)

toUcantoSigner() supports an optional domainLabel override:

  • OrbitDB entry signing: use the default domain label (orbitdb-entry:).
  • UCAN flows that require a protocol-specific challenge prefix: pass it explicitly (for example ucan-webauthn-v1:).
// OrbitDB-style default (no override)
const orbitdbUcantoSigner = signer.toUcantoSigner();

// UCAN-specific override
const ucanUcantoSigner = signer.toUcantoSigner({
  domainLabel: 'ucan-webauthn-v1:',
});

The verifier side and app protocol should define which domain label is required. IPFS deployment does not change this requirement.

Keystore-based DID (WebAuthn + OrbitDB keystore)

sequenceDiagram
  autonumber
  participant User
  participant App
  participant WebAuthn
  participant Auth as Authenticator
  participant KS as OrbitDB Keystore
  participant Enc as KeystoreEncryption
  participant DB as OrbitDB

  User->>App: Create credential
  App->>WebAuthn: create()
  WebAuthn->>Auth: Create passkey
  Auth-->>WebAuthn: Attestation
  WebAuthn-->>App: Credential

  App->>KS: getKey()/createKey(Ed25519)
  KS-->>App: Keystore keypair

  opt encryptKeystore=true
    App->>Enc: generateSecretKey()
    Enc-->>App: sk
    App->>Enc: encrypt keystore private key (AES-GCM)
    alt prf
      App->>WebAuthn: get() with PRF
      WebAuthn->>Auth: User verification
      Auth-->>WebAuthn: PRF output
      WebAuthn-->>App: PRF bytes
      App->>Enc: wrap sk with PRF
    else largeBlob
      App->>WebAuthn: get() with largeBlob write
      WebAuthn->>Auth: User verification
      Auth-->>WebAuthn: Store sk in largeBlob
      WebAuthn-->>App: largeBlob stored
    else hmac-secret
      App->>WebAuthn: get() with hmac-secret
      WebAuthn->>Auth: User verification
      Auth-->>WebAuthn: HMAC output
      WebAuthn-->>App: HMAC bytes
      App->>Enc: wrap sk with HMAC
    end
  end

  App->>DB: db.put()
  DB->>KS: sign entry with keystore key
  KS-->>DB: Entry signature

  Note over App,KS: Keystore private key is encrypted at rest when `encryptKeystore=true`.

Varsig (no keystore)

sequenceDiagram
  autonumber
  participant User
  participant App
  participant WebAuthn
  participant Auth as Authenticator
  participant Var as Varsig Provider
  participant DB as OrbitDB

  User->>App: Create credential
  App->>WebAuthn: create()
  WebAuthn->>Auth: Create passkey
  Auth-->>WebAuthn: Attestation
  WebAuthn-->>App: Credential

  User->>App: Create varsig identity
  App->>Var: createIdentity()
  Var->>WebAuthn: get()
  WebAuthn->>Auth: User verification
  Auth-->>WebAuthn: Assertion
  WebAuthn-->>Var: Assertion
  Var->>Var: encode varsig envelope
  Var-->>App: Identity

  User->>App: Add entry
  App->>DB: db.put()
  DB->>Var: signIdentity(payload)
  Var->>WebAuthn: get()
  WebAuthn->>Auth: User verification
  Auth-->>WebAuthn: Assertion
  WebAuthn-->>Var: Assertion
  Var->>Var: encode varsig envelope
  Var-->>DB: Varsig signature

Examples

Svelte demos:

  • examples/webauthn-todo-demo/ - WebAuthn DID (no keystore signing; identity-only). Includes discoverable credential diagnostics, Use Existing Passkey, largeBlob identity metadata recovery, and local fallback recovery.
  • examples/ed25519-encrypted-keystore-demo/ - Ed25519 keystore DID; keystore encrypted at rest with WebAuthn (PRF when available, otherwise largeBlob/hmac-secret).
  • examples/webauthn-varsig-demo/ - Varsig provider with passkey signing for each entry. Includes discoverable credential diagnostics, Use Existing Passkey, largeBlob varsig metadata recovery, and local fallback recovery. Live demo: https://dweb.link/ipfs/bafybeib6tpwiby7pik67ufb3lxpr3j4by2l7r3ov3zzk6hjbzjzgsvckhy

Scripted examples:

  • examples/ed25519-keystore-did-example.js - Keystore DID flow.
  • examples/encrypted-keystore-example.js - Keystore encryption flow.
  • examples/simple-encryption-integration.js - Keystore + database content encryption.

Mermaid sequences for scripts:

  • docs/EXAMPLE-SEQUENCES.md

Documentation

  • docs/ED25519-KEYSTORE-DID.md
  • docs/WEBAUTHN-ENCRYPTED-KEYSTORE-INTEGRATION.md
  • docs/WEBAUTHN-DID-AND-ORBITDB-IDENTITY.md
  • docs/STANDALONE-API-PLAN.md
  • docs/EXAMPLE-SEQUENCES.md
  • docs/E2E-TEST-SUMMARY.md

Identity Recovery Summary

Current identity recovery behavior in this repo:

  • Discoverable passkeys are the default.
  • Discoverable authentication can recover the credential ID used for assertion.
  • Discoverable authentication does not reliably re-expose the credential public key.
  • Because of that, OrbitDB identity recovery requires metadata persistence.
  • The demos now try largeBlob first for identity metadata recovery.
  • If largeBlob is not supported or has no metadata, the demos fall back to local browser storage.

Practical implication:

  • If you create a passkey on one browser profile and later open the app in a fresh profile, the passkey may still exist in the platform passkey manager, but the app can only reconstruct the OrbitDB identity if it can recover metadata from largeBlob or some other persisted mapping.

License

MIT. See LICENSE.