Authentication
Simple guide to LazorKit's passkey-based wallet authentication.
Quick Start
LazorKit uses WebAuthn passkeys instead of seed phrases - more secure and user-friendly.
import { useWallet } from '@lazorkit/wallet';
function WalletConnect() {
const { connect, account, isConnecting } = useWallet();
return (
<button onClick={connect} disabled={isConnecting}>
{account ? `Connected: ${account.smartWallet.slice(0, 8)}...` : 'Connect Wallet'}
</button>
);
}
How It Works
Passkeys = Device biometrics (Face ID, fingerprint) + secure hardware storage
- First time: Create passkey → Deploy smart wallet
- Return visits: Authenticate → Reconnect automatically
- Transactions: Biometric approval → Sign & send
Browser Support: Chrome 88+, Safari 15+, Firefox 90+, Edge 88+
Connection Patterns
Standard Connection (Recommended)
const { connect, account, isConnecting, error } = useWallet();
const handleConnect = async () => {
try {
const account = await connect(); // Auto-handles new/existing users
console.log('Connected:', account.smartWallet);
} catch (error) {
console.error(error.code); // 'NO_STORED_CREDENTIALS' | 'USER_CANCELLED'
}
};
Auto-Connect on App Load
function App() {
const { connect, isConnected } = useWallet();
useEffect(() => {
if (!isConnected) {
connect().catch(error => {
if (error.code !== 'NO_STORED_CREDENTIALS') {
console.error('Auto-connect failed:', error);
}
});
}
}, []);
return <YourApp />;
}
Error Handling
Simple error patterns for common scenarios:
const handleAuthError = (error) => {
switch (error.code) {
case 'NO_STORED_CREDENTIALS':
return 'Welcome! Ready to create your first wallet?';
case 'USER_CANCELLED':
return 'Authentication cancelled. Try again when ready.';
case 'PASSKEY_CREATION_FAILED':
return 'Failed to create passkey. Check browser settings.';
default:
return 'Authentication failed. Please try again.';
}
};
// Usage
try {
await connect();
} catch (error) {
setMessage(handleAuthError(error));
}
Advanced Patterns
Custom Onboarding
function OnboardingFlow() {
const { createPasskeyOnly, createSmartWalletOnly } = useWallet();
const [step, setStep] = useState<'passkey' | 'wallet' | 'complete'>('passkey');
const [passkeyData, setPasskeyData] = useState(null);
const steps = {
passkey: async () => {
const data = await createPasskeyOnly();
setPasskeyData(data);
setStep('wallet');
},
wallet: async () => {
await createSmartWalletOnly(passkeyData);
setStep('complete');
}
};
return (
<div>
{step === 'passkey' && <button onClick={steps.passkey}>Create Passkey</button>}
{step === 'wallet' && <button onClick={steps.wallet}>Deploy Wallet</button>}
{step === 'complete' && <div>✅ Wallet Ready!</div>}
</div>
);
}
External Payer Pattern
function ExternalPayerTransaction() {
const { buildSmartWalletTransaction, smartWalletPubkey } = useWallet();
const sendWithExternalPayer = async () => {
const instruction = SystemProgram.transfer({
fromPubkey: smartWalletPubkey,
toPubkey: new PublicKey(process.env.REACT_APP_RECIPIENT_ADDRESS!),
lamports: 1000000, // 0.001 SOL
});
const { createSessionTx, executeSessionTx } = await buildSmartWalletTransaction(
new PublicKey(process.env.REACT_APP_EXTERNAL_PAYER_ADDRESS!),
instruction
);
// Send to backend for signing
await fetch('/api/external-payer/sign', {
method: 'POST',
body: JSON.stringify({
sessionTx: Buffer.from(createSessionTx.serialize()).toString('base64'),
executeTx: Buffer.from(executeSessionTx.serialize()).toString('base64'),
}),
});
};
return <button onClick={sendWithExternalPayer}>Send (External Payer)</button>;
}
Security & Compatibility
What's Secure
- ✅ Private keys: Stored in device secure hardware (never in browser)
- ✅ Biometric auth: Required for every transaction
- ✅ Cross-origin protection: Passkeys bound to your domain
- ✅ No seed phrases: Nothing to lose or leak
Browser Compatibility
// Feature detection (optional)
const supportsPasskeys = !!(navigator.credentials && navigator.credentials.create);
function CompatibilityCheck() {
if (!supportsPasskeys) {
return <div>Please use Chrome 88+, Safari 15+, or Firefox 90+</div>;
}
return <WalletConnection />;
}
Platform Notes
- iOS: Requires iOS 16+ for full passkey support
- Android: Works with Android 9+ and device screen lock
- Desktop: Hardware security keys supported
- Private browsing: Limited functionality
Best Practices
- Always HTTPS - Required for WebAuthn
- User-initiated - Don't auto-trigger authentication
- Clear errors - Use the error codes to guide users
- Test thoroughly - Behavior varies across devices
- Graceful fallback - Handle unsupported browsers