Implement passkey-based wallet authentication in React Native with deep linking.
This example shows how to:
- Connect a wallet using Face ID / Touch ID
- Handle deep link redirects after authentication
- Display wallet address and balances
- Request devnet airdrops
This cookbook provides a WalletContext wrapper that simplifies the LazorKit SDK API. Instead of manually constructing redirect URLs, you just pass a path:
import { useLazorkitWalletConnect } from '@/hooks/useLazorkitWalletConnect';
function ConnectScreen() {
const { wallet, isConnected, connect, disconnect, connecting } = useLazorkitWalletConnect();
const handleConnect = () => {
// Just pass the return path - WalletContext handles redirectUrl
connect('examples/01-connect-wallet');
};
if (connecting) {
return <Text>Connecting...</Text>;
}
if (isConnected) {
return (
<View>
<Text>Connected: {wallet?.smartWallet}</Text>
<Button title="Disconnect" onPress={disconnect} />
</View>
);
}
return <Button title="Connect" onPress={handleConnect} />;
}You can also use the SDK without our wrapper:
import { useWallet } from '@lazorkit/wallet-mobile-adapter';
import * as Linking from 'expo-linking';
function ConnectScreen() {
const { wallet, isConnected, connect, disconnect } = useWallet();
const [connecting, setConnecting] = useState(false);
const handleConnect = async () => {
setConnecting(true);
await connect({
redirectUrl: Linking.createURL('examples/01-connect-wallet'),
onSuccess: (connectedWallet) => {
setConnecting(false);
console.log('Connected:', connectedWallet.smartWallet);
},
onFail: (error) => {
setConnecting(false);
Alert.alert('Connection Failed', error.message);
},
});
};
// ... rest of component
}Unlike web where LazorKit opens a popup, mobile uses deep links:
- Your app calls
connect()with aredirectUrl - External browser opens to LazorKit portal
- User authenticates with Face ID/Touch ID
- Browser redirects back to your app via deep link
onSuccesscallback fires with wallet data
import * as Clipboard from 'expo-clipboard';
import { Linking } from 'react-native';
// Copy address to clipboard
await Clipboard.setStringAsync(wallet.smartWallet);
Alert.alert('Copied', 'Address copied to clipboard');
// Open Solana Explorer
Linking.openURL(
`https://explorer.solana.com/address/${wallet.smartWallet}?cluster=devnet`
);import { useBalances } from '@/hooks/useBalances';
const { solBalance, usdcBalance, loading, fetchBalances } = useBalances(
isConnected ? wallet?.smartWallet : null
);
<ScrollView
refreshControl={
<RefreshControl refreshing={loading} onRefresh={fetchBalances} />
}
>
<Text>SOL: {solBalance?.toFixed(4)}</Text>
<Text>USDC: {usdcBalance?.toFixed(2)}</Text>
</ScrollView>See the complete implementation at:
mobile/app/examples/01-connect-wallet/index.tsx
- Gasless Transfer - Send USDC without gas fees
- Raydium Swap - DEX integration