Passkeys are the most important UX upgrade for wallets since mobile. Instead of seed phrases and browser extensions, users authenticate with the same biometrics they already use every day: Face ID, Touch ID, or Windows Hello.
This post walks through a minimal Vite + React demo that uses the LazorKit SDK to:
- Create a passkey-based smart wallet
- Display the wallet address
- Send a standard SOL transfer on devnet
This is an example demo, not a full product. LazorKit is pre-audit—don’t use it in production.
Why passkeys for Solana
Traditional wallets require users to:
- Install a third‑party extension or app
- Save (and never lose) a seed phrase
- Jump through popups and approvals
Passkeys flip this flow:
- The private key stays in secure hardware (device enclave)
- Users authenticate with biometrics
- The browser handles the UX
That’s the closest we have to “Web2 login” on-chain.
What we’re building
A single-page demo with three sections:
- Passkey connect (create or restore)
- Airdrop (optional devnet funding)
- SOL transfer (standard tx, signed by passkey)
Everything is intentionally small and readable.
Core idea: wrap your app in LazorKit
The provider handles the passkey flow and smart wallet management.
import { LazorkitProvider } from '@lazorkit/wallet';
export default function App() {
return (
<LazorkitProvider
rpcUrl="https://api.devnet.solana.com"
portalUrl="https://portal.lazor.sh"
>
<YourApp />
</LazorkitProvider>
);
}
From here, you can use the useWallet hook anywhere.
Passkey connect flow
import { useWallet } from '@lazorkit/wallet';
export function ConnectButton() {
const { connect, disconnect, isConnected, wallet } = useWallet();
if (isConnected && wallet) {
return <button onClick={() => disconnect()}>Disconnect</button>;
}
return <button onClick={() => connect({ feeMode: 'paymaster' })}>Connect</button>;
}
When connect() runs, the browser prompts for passkey creation or authentication. No seed phrase, no extension.
Sending SOL (standard transaction)
import { useWallet } from '@lazorkit/wallet';
import { SystemProgram, PublicKey, LAMPORTS_PER_SOL } from '@solana/web3.js';
const { signAndSendTransaction, smartWalletPubkey } = useWallet();
const destination = new PublicKey('RECIPIENT_ADDRESS');
const instruction = SystemProgram.transfer({
fromPubkey: smartWalletPubkey,
toPubkey: destination,
lamports: 0.01 * LAMPORTS_PER_SOL
});
const signature = await signAndSendTransaction({
instructions: [instruction]
});
This is a regular devnet transfer. It requires SOL for fees. (Paymaster support is optional and not included in this demo.)
What the demo includes
- Passkey connect + disconnect
- Smart wallet address display
- Copy‑to‑clipboard for wallet address
- Recipient input with
.envdefault - Optional devnet airdrop button
- Readable docs + tutorials
How to run it
npm install
cp .env.example .env
npm run dev
Then open the Vite URL and click Connect Passkey Wallet.
Repo structure (high‑level)
src/
components/
ConnectButton.jsx
AirdropButton.jsx
TransferButton.jsx
StatusPanel.jsx
lib/config.js
App.jsx
main.jsx
What’s next
This demo is intentionally minimal. Some easy next steps:
- Add SPL token transfers (USDC)
- Integrate a swap aggregator (e.g., Jupiter)
- Add session management or device recovery UX
References
- LazorKit Docs: https://docs.lazorkit.com/
- LazorKit GitHub: https://github.com/lazor-kit/lazor-kit
- Repo Github : https://github.com/FredMunene/sollaz
If you’re building Solana UX in 2026, passkeys aren’t optional anymore; they’re the baseline.
Top comments (0)