Skip to content

w3hc/w3pk

npm version npm downloads Reproducible Build

w3pk

Passwordless Web3 authentication SDK with encrypted wallets and privacy features.

Live demo: w3pk.w3hc.org

Install

npm install w3pk ethers

Quick Start

import { createWeb3Passkey } from 'w3pk'

const w3pk = createWeb3Passkey()

// Register new user (generates wallet, stores with WebAuthn)
const { address, username } = await w3pk.register({ username: 'alice' })

// Login for subsequent sessions
await w3pk.login()

// Sign messages (EIP-191, SIWE, EIP-712, rawHash)
const signature = await w3pk.signMessage('Hello World')

// Derive wallets (STANDARD/STRICT/YOLO modes)
const wallet = await w3pk.deriveWallet('STANDARD', 'GAMING')

// Get RPC endpoints
const endpoints = await w3pk.getEndpoints(1)

Features

  • Passwordless authentication (WebAuthn/FIDO2)
  • Origin-specific key isolation with tag-based access control
  • Session management (in-memory + optional persistent)
  • HD wallet generation (BIP39/BIP44)
  • Multi-address derivation with security modes (STANDARD/STRICT/YOLO)
  • Multiple signing methods (EIP-191, SIWE/EIP-4361, EIP-712, rawHash)
  • ERC-5564 stealth addresses (opt-in)
  • ZK primitives (zero-knowledge proof generation and verification)
  • Chainlist support (2390+ networks)
  • EIP-7702 network detection (329+ networks)
  • External wallet integration (delegate MetaMask/Ledger to w3pk via EIP-7702)
  • EIP-7951 PRIMARY mode (P-256 passkey signing)
  • Build verification (IPFS CIDv1 hashing)
  • Three-layer backup & recovery (passkey sync, encrypted backups, social recovery)

API

Authentication

// Check for existing wallet
const hasWallet = await w3pk.hasExistingCredential()

// Register or login
if (hasWallet) {
  await w3pk.login()
} else {
  const { address, username } = await w3pk.register({ username: 'alice' })
}

// List all wallets on device
const wallets = await w3pk.listExistingCredentials()

// Logout
await w3pk.logout()

Wallet Derivation

// STANDARD mode - address only (no private key)
const mainWallet = await w3pk.deriveWallet('STANDARD')
// Returns: { address, index, origin, tag: 'MAIN' }

// YOLO mode - includes private key for app-specific use
const gamingWallet = await w3pk.deriveWallet('YOLO', 'GAMING')
// Returns: { address, privateKey, index, origin, tag: 'GAMING' }

// STRICT mode - address only, no persistent sessions allowed
const strictWallet = await w3pk.deriveWallet('STRICT', 'SECURE')

// Different tags generate different addresses
console.log(mainWallet.address !== gamingWallet.address) // true

Security: Master mnemonic is never exposed. Applications cannot access exportMnemonic().

Message Signing

// EIP-191 (default)
const sig = await w3pk.signMessage('Hello World')

// SIWE (Sign-In with Ethereum)
const siweMessage = createSiweMessage({ ... })
const siweSig = await w3pk.signMessage(siweMessage, {
  signingMethod: 'SIWE'
})

// EIP-712 (typed data)
const eip712Sig = await w3pk.signMessage(JSON.stringify(typedData), {
  signingMethod: 'EIP712',
  eip712Domain,
  eip712Types,
  eip712PrimaryType: 'Transfer'
})

// Raw hash
const rawSig = await w3pk.signMessage(hash, {
  signingMethod: 'rawHash'
})

// Force authentication for sensitive operations
const sensitiveSig = await w3pk.signMessage('Transfer $1000', {
  requireAuth: true
})

Session Management

// In-memory sessions (default, 1 hour)
const w3pk = createWeb3Passkey({
  sessionDuration: 2 // 2 hours
})

// Persistent sessions (survives page refresh)
const w3pkPersistent = createWeb3Passkey({
  sessionDuration: 1,
  persistentSession: {
    enabled: true,
    duration: 168,        // 7 days (in hours)
    requireReauth: true   // Prompt on refresh
  }
})

// Auto-restore mode (silent restore)
const w3pkAutoRestore = createWeb3Passkey({
  persistentSession: {
    enabled: true,
    duration: 30 * 24,
    requireReauth: false
  }
})

// Session status
w3pk.hasActiveSession()
w3pk.getSessionRemainingTime()
w3pk.extendSession()
await w3pk.clearSession()

Note: STRICT mode never allows persistent sessions.

RPC Endpoints

// Get public RPC endpoints for any chain
const endpoints = await w3pk.getEndpoints(1)      // Ethereum
const optimismRpc = await w3pk.getEndpoints(10)   // Optimism
const arbitrumRpc = await w3pk.getEndpoints(42161) // Arbitrum

// Use with ethers.js
import { ethers } from 'ethers'
const provider = new ethers.JsonRpcProvider(endpoints[0])
const blockNumber = await provider.getBlockNumber()

EIP-7702 Support

// Check network support
const supported = await w3pk.supportsEIP7702(1)

// Configure RPC testing
await w3pk.supportsEIP7702(999, {
  maxEndpoints: 5,
  timeout: 5000
})

// Sign authorization for gasless transactions
const authorization = await w3pk.signAuthorization({
  contractAddress: '0x...',
  chainId: 1,
  nonce: 0n
})
// Returns: { chainId, address, nonce, yParity, r, s }

// Delegate external wallet (MetaMask, Ledger, etc.) to w3pk account
const auth = await w3pk.requestExternalWalletDelegation({
  chainId: 1,
  nonce: 0n
})
// User's external wallet account now controlled by w3pk WebAuthn

EIP-7951 PRIMARY Mode

// Get PRIMARY address (P-256 passkey-derived)
const primaryAddr = await w3pk.getAddress('PRIMARY')

// Sign with P-256 passkey directly (no private key)
const result = await w3pk.signMessageWithPasskey("Hello World")
// Returns: { signature: { r, s }, messageHash, signedHash, address }

ERC-5564 Stealth Addresses

const w3pk = createWeb3Passkey({
  stealthAddresses: {}
})

// Get stealth meta-address
const metaAddress = await w3pk.stealth?.getStealthMetaAddress()

// Generate stealth address for recipient
const announcement = await w3pk.stealth?.generateStealthAddress()

// Check if announcement is for you
const result = await w3pk.stealth?.parseAnnouncement({
  stealthAddress: announcement.stealthAddress,
  ephemeralPublicKey: announcement.ephemeralPublicKey,
  viewTag: announcement.viewTag
})

if (result.isForUser) {
  console.log('Private key:', result.stealthPrivateKey)
}

// Scan multiple announcements
const myPayments = await w3pk.stealth?.scanAnnouncements(announcements)

Backup & Recovery

import { isStrongPassword } from 'w3pk'

// Validate password strength
const password = 'MyS3cur3!Password@2042'
if (!isStrongPassword(password)) {
  throw new Error('Password must be 12+ chars with uppercase, lowercase, number, special char')
}

// Get backup status
const status = await w3pk.getBackupStatus()
console.log('Security Score:', status.securityScore.total) // 0-100

// Create encrypted backup file
const { blob, filename } = await w3pk.createBackupFile('password', password)

// Setup social recovery (M-of-N guardians)
await w3pk.setupSocialRecovery(
  [
    { name: 'Alice', email: 'alice@example.com' },
    { name: 'Bob', phone: '+1234567890' },
    { name: 'Charlie' }
  ],
  2 // threshold
)

// Generate guardian invite
const invite = await w3pk.generateGuardianInvite(guardianShare)

// Recover from guardian shares
const { mnemonic } = await w3pk.recoverFromGuardians([share1, share2])

// Restore from backup file
await w3pk.restoreFromBackupFile(encryptedData, password)

// Simulate recovery scenarios
const result = await w3pk.simulateRecoveryScenario({
  type: 'lost-device',
  description: 'Device lost with iCloud Keychain enabled'
})

Build Verification

import { getCurrentBuildHash, verifyBuildHash } from 'w3pk'

// Get IPFS hash of installed build
const hash = await getCurrentBuildHash()

// Verify against trusted hash
const TRUSTED_HASH = 'bafybeig2xoiu2hfcjexz6cwtjcjf4u4vwxzcm66zhnqivhh6jvi7nx2qa4'
const isValid = await verifyBuildHash(TRUSTED_HASH)

Security & Verification

Current Build Hash (v0.8.8)

bafybeig2xoiu2hfcjexz6cwtjcjf4u4vwxzcm66zhnqivhh6jvi7nx2qa4

Verify package integrity:

import { verifyBuildHash } from 'w3pk'

const TRUSTED_HASH = 'bafybeig2xoiu2hfcjexz6cwtjcjf4u4vwxzcm66zhnqivhh6jvi7nx2qa4'
const isValid = await verifyBuildHash(TRUSTED_HASH)

if (!isValid) {
  throw new Error('Package integrity check failed!')
}

Documentation

Contributing

See CONTRIBUTING.md

License

GPL-3.0

Contact

Julien Béranger (GitHub)

built-with-ethereum-w3hc