Documentation Index
Fetch the complete documentation index at: https://docs.chipipay.com/llms.txt
Use this file to discover all available pages before exploring further.
Why migrate
PIN-encrypted wallets are the shortest path to a working integration, but they are not the right default for production. A 6-digit PIN has roughly 20 bits of entropy — an attacker who obtains the encrypted ciphertext (e.g. via a leaky metadata field, a stolen backup, or any other ciphertext exposure) can brute-force it offline in seconds. Passkey authentication removes this vector:- The encryption key is derived from a hardware-backed WebAuthn credential (Face ID, Touch ID, Windows Hello, security key).
- It never leaves the device’s secure element.
- There is no low-entropy secret to crack.
useMigrateWalletToPasskey.
Recommended for all production wallets. New wallets should be created with
usePasskey: true from the start (see the Passkeys guide). This guide covers existing wallets that were created PIN-only.Prerequisites
- Wallet was created with a PIN (
encryptKey) and currently has onlyencryptedPrivateKeyset. - User is on a device that supports WebAuthn PRF (most modern browsers + Face ID / Touch ID / Windows Hello).
- App is using
@chipi-stack/nextjs≥ v14.3.0 (which ships dual-key support for new wallets) or@chipi-stack/chipi-react≥ v14.3.0. @chipi-stack/chipi-passkeyis installed.
How migration works
useMigrateWalletToPasskey performs an atomic key swap:
- The user’s current PIN is used to decrypt
encryptedPrivateKeylocally — if the PIN is wrong, migration aborts before touching anything else. - A new passkey is created via WebAuthn (biometric prompt).
- The decrypted private key is re-encrypted using the passkey-derived key.
- The new ciphertext is sent to the backend via
PATCH /chipi-wallets/update-encryption-details. - The hook returns the updated wallet and the
credentialId— persist both.
Migration component
After migration
Once migration succeeds:wallet.encryptedPrivateKeyis now passkey-encrypted.- All subsequent signing flows must use
usePasskey: true. For example:
- Store
credentialIdsomewhere durable (your DB, ClerkprivateMetadatavia a server route, etc.). IflocalStorageis cleared, the SDK can recover the credential from the backend via/chipi-wallets/credential-recovery.
A note on PIN backup
useMigrateWalletToPasskey performs a single-key swap — after migration, the backend stores only the passkey-encrypted ciphertext. A wallet that was created PIN-only does not gain a PIN backup column through migration.
If you want true dual-key (passkey primary, PIN backup), the path is to create new wallets with usePasskey: true from the start (see Passkeys → Create Wallet with Passkey + PIN). This sets both encryptedPrivateKey (passkey) and encryptedPrivateKeyBackup (PIN) at creation time, and the SDK’s useTransfer will automatically fall back to PIN if the passkey is unavailable.
For migrated wallets, plan for passkey recovery via WebAuthn discoverable credentials and credentialId recovery rather than a PIN fallback.
Rollout strategy
A staged rollout reduces risk:- Detect. On wallet load, check whether the wallet has a
credentialId/ passkey-encrypted state. If not, surface a one-time migration prompt. - Prompt at a low-stakes moment. Don’t block the user mid-transfer. Show the upgrade flow on the next wallet screen visit, or after a successful (non-critical) action.
- Make it non-mandatory at first. Let users skip and re-prompt later. Track adoption.
- Mandate for high-value flows. Once adoption is high, gate sensitive flows (large transfers, treasury actions) behind passkey-only wallets.
- Monitor. Log migration attempts, successes, failures, and PRF-not-supported events so you can size the long tail.
Errors and edge cases
| Error | Cause | What to do |
|---|---|---|
Failed to decrypt wallet with provided encryptKey | User entered the wrong PIN | Re-prompt; do not retry the passkey creation step |
| WebAuthn aborted / cancelled | User dismissed the biometric prompt | No state changed — safe to retry |
Backend rejected wallet encryption update | Network or auth failure mid-update | The backend write is atomic; retry the full migration |
| PRF not supported | Device/browser does not support WebAuthn PRF | Keep the user on PIN; surface the migration option only when PRF is detected |
Related
- Passkeys guide — full passkey + dual-key architecture
useMigrateWalletToPasskey— hook referenceuseUpdateWalletEncryption— lower-level encryption updateuseChipiSession— session keys with secure server-side storage
