The React hooks (
usePasskeySetup, usePasskeyAuth, usePasskeyStatus) wrap the PRF surface (the default STARK-signer wallets) today. SHHH equivalents ship in a follow-on release; until then, call createShhhPasskey / signShhhMessage directly inside your own effects.
SHHH passkey (modern path)
createShhhPasskey
Registers a new P-256 platform passkey. No PRF extension, no PIN derivation. The private key stays inside the platform authenticator.rpId = window.location.hostname, rpName = "Chipi Wallet". Persists { credentialId, publicKey, userId, rpId, transports } to localStorage under the key chipi_wallet_shhh_passkey_credential. Throws on NotAllowedError (user cancelled) or InvalidStateError (passkey already exists for this account on this device).
signShhhMessage
Runsnavigator.credentials.get() with messageHash encoded as the 32-byte big-endian WebAuthn challenge. Returns the raw assertion bytes ready to feed into buildWebAuthnEnvelopeFromAssertion from @chipi-stack/backend.
hasShhhPasskey
Synchronous check for a stored SHHH credential. Use it to branch between “Sign up” and “Sign in” UI without prompting.getStoredShhhCredential
Reads the persisted credential metadata.removeStoredShhhCredential
Clears the stored credential id from localStorage. Use at logout, account reset, or when the user opts to re-register. The platform authenticator’s stored credential is NOT deleted — only your app’s reference to it.Extraction utilities
Exported for tests and for advanced callers who want to verify a passkey’s pubkey against a separately-stored copy.extractP256PubkeyFromRegistration is the dispatch helper — it tries the SPKI fast path first (Chrome, Safari, modern Edge), then falls back to decoding the CBOR attestationObject for older browsers. You only need these utilities if you’re writing your own registration-response handler.
PRF passkey [#legacy-prf-passkey]
The PRF passkey path encrypts a STARK private key with a key derived from the WebAuthn PRF extension. It backsuseCreateWallet({ usePasskey: true }), which creates an SHHH wallet with a STARK signer by default (the kind that supports session keys), and CHIPI v29 wallets. A PIN backup (dual-key, passkey primary + PIN backup) is optional. SHHH wallets with a WEBAUTHN_P256 signer use createShhhPasskey above instead.
To unlock on a device where this browser did not create the passkey, pass the credentialId and prfSupported stored on the wallet row: getWalletEncryptKey(wallet.credentialId ?? undefined, { prfSupported: wallet.prfSupported ?? undefined }). With no argument it reads localStorage and throws "No wallet passkey found" on a new device.
createWalletPasskey
Registers a passkey with the PRF extension enabled, derives an encryption key from the PRF output, and stores the credential metadata.{ credentialId, createdAt, userId, transports, prfSupported } to localStorage under chipi_wallet_passkey_credential. Separate storage key from the SHHH path — both surfaces coexist on the same device.
requirePrf (default true) makes creation refuse a non-self-custodial wallet. On an authenticator that cannot produce a WebAuthn PRF secret, the only fallback is a key derived from PBKDF2(credentialId, userId); both are values your backend stores, so the derived wrap key is server-recomputable and the wallet is effectively custodial. With requirePrf at its default, createWalletPasskey throws PrfUnsupportedError (.code === "PRF_UNSUPPORTED") instead of creating that wallet. Catch it and tell the user their device can’t secure a wallet. Pass { requirePrf: false } only to knowingly opt into the custodial fallback (never for self-custodial consumer wallets). Also throws on NotAllowedError (cancelled) and InvalidStateError (passkey already exists). Unlocking existing non-PRF wallets via getWalletEncryptKey is unaffected.
getWalletEncryptKey
Authenticates with an existing PRF passkey and returns the sameencryptKey derived at registration time. Use it before every wallet operation that needs the STARK key (transfer, session-key registration, encryption rotation).
Status checks
Credential management
React hooks (PRF passkey path) [#react-hooks-legacy-passkey-path]
The hooks today wrap the PRF surface —usePasskeySetup calls createWalletPasskey, usePasskeyAuth calls getWalletEncryptKey. Import from the /hooks subpath so Next.js bundles get the right "use client" directives.
usePasskeySetup
usePasskeyAuth
usePasskeyStatus
TypeScript types
Related
- Quickstart — end-to-end SHHH passkey flow
- When passkeys fail — recovery, PIN fallback, browser switching
