Overview
WebAuthn passkeys replace PINs with biometric authentication (Face ID, Touch ID, Windows Hello). No PINs to remember or store.
Prerequisites
- Modern browser with WebAuthn support (Chrome, Safari, Firefox, Edge)
- Biometric hardware (fingerprint, face recognition)
- Chipi React SDK installed
Installation
npm install @chipi-stack/chipi-passkey
Basic Implementation
Create wallet with passkey
import { usePasskeySetup } from "@chipi-stack/chipi-react";
Authenticate with passkey
import { usePasskeyAuth } from "@chipi-stack/chipi-react";
Migrate existing wallet (optional)
If users already have a PIN-based wallet, they can migrate to passkey:import { useMigrateWalletToPasskey } from "@chipi-stack/chipi-react";
Example
Create Wallet
Transfer with Passkey
Migrate to Passkey
import { useCreateWallet } from '@chipi-stack/chipi-react';
import { usePasskeySetup } from '@chipi-stack/chipi-react';
import { useState } from 'react';
export function CreateWalletWithPasskey() {
const { createWalletAsync, isLoading, error } = useCreateWallet();
const { setupPasskey } = usePasskeySetup();
const [wallet, setWallet] = useState(null);
const handleCreate = async () => {
try {
// Triggers biometric prompt
const encryptKey = await setupPasskey();
const result = await createWalletAsync({
params: {
encryptKey,
usePasskey: true,
externalUserId: 'user-123',
},
bearerToken: 'your-jwt-token',
});
localStorage.setItem('wallet', JSON.stringify(result.wallet));
setWallet(result);
} catch (err) {
console.error(err);
}
};
return (
<div>
<button onClick={handleCreate} disabled={isLoading}>
{isLoading ? 'Creating...' : 'Create Wallet with Passkey'}
</button>
{error && <p>Error: {error.message}</p>}
{wallet && <p>Wallet created: {wallet.wallet.publicKey}</p>}
</div>
);
}
import { useTransfer } from '@chipi-stack/chipi-react';
import { usePasskeyAuth } from '@chipi-stack/chipi-react';
import { useState } from 'react';
export function TransferWithPasskey() {
const { transferAsync, isLoading } = useTransfer();
const { authenticatePasskey } = usePasskeyAuth();
const [recipient, setRecipient] = useState('');
const [amount, setAmount] = useState('');
const handleTransfer = async () => {
try {
// Triggers biometric prompt
const encryptKey = await authenticatePasskey();
const wallet = JSON.parse(localStorage.getItem('wallet')!);
const txHash = await transferAsync({
params: {
encryptKey,
usePasskey: true,
wallet,
token: 'USDC',
recipient,
amount: Number(amount),
},
bearerToken: 'your-jwt-token',
});
alert(`Transfer complete: ${txHash}`);
} catch (err) {
console.error(err);
}
};
return (
<div>
<input
placeholder="Recipient address"
value={recipient}
onChange={(e) => setRecipient(e.target.value)}
/>
<input
placeholder="Amount"
value={amount}
onChange={(e) => setAmount(e.target.value)}
type="number"
/>
<button onClick={handleTransfer} disabled={isLoading}>
{isLoading ? 'Sending...' : 'Send with Passkey'}
</button>
</div>
);
}
import { useMigrateWalletToPasskey } from '@chipi-stack/chipi-react';
import { usePasskeySetup } from '@chipi-stack/chipi-react';
import { useState } from 'react';
export function MigrateToPasskey() {
const { migrateWalletToPasskeyAsync, isLoading } = useMigrateWalletToPasskey();
const { setupPasskey } = usePasskeySetup();
const [currentPin, setCurrentPin] = useState('');
const handleMigrate = async () => {
try {
const newEncryptKey = await setupPasskey();
const wallet = JSON.parse(localStorage.getItem('wallet')!);
await migrateWalletToPasskeyAsync({
params: {
oldEncryptKey: currentPin,
newEncryptKey,
wallet,
},
bearerToken: 'your-jwt-token',
});
alert('Successfully migrated to passkey!');
} catch (err) {
console.error(err);
}
};
return (
<div>
<input
type="password"
placeholder="Current PIN"
value={currentPin}
onChange={(e) => setCurrentPin(e.target.value)}
/>
<button onClick={handleMigrate} disabled={isLoading}>
{isLoading ? 'Migrating...' : 'Migrate to Passkey'}
</button>
</div>
);
}
Hooks Reference
| Hook | Purpose |
|---|
usePasskeySetup | Create new passkey |
usePasskeyAuth | Authenticate with existing passkey |
usePasskeyStatus | Check passkey support & status |
useMigrateWalletToPasskey | Migrate from PIN to passkey |
Browser Support
- ✅ Chrome 67+ (Desktop & Android)
- ✅ Safari 14+ (iOS 14+, macOS)
- ✅ Firefox 60+ (Desktop)
- ✅ Edge 18+ (Desktop)
Passkeys are stored in the browser and synced via platform (iCloud Keychain, Google Password Manager).
Security Benefits
- No PINs stored - Keys derived on-demand from biometric
- Platform-level security - Hardware-backed authentication
- Phishing resistant - Domain-bound credentials
- User convenience - One tap authentication
Next Steps