Biconomy Passkey SDK Integration Guide
Why use Passkeys?
Developers can leverage Passkeys to enable their users to sign transactions and log in with FaceID or Fingerprints. This reduces a major point of friction when interacting with blockchain as it enables users to store their private key within the Hardware Secure enclave provided by computer and smartphone manufacturers such as Apple.
This guide demonstrates how to integrate the Biconomy SDK with passkey authentication in a client-side application.
Setup Environment Variables
Create a .env
file with your Biconomy configuration:
NEXT_PUBLIC_BUNDLER_URL=your_bundler_url
NEXT_PUBLIC_PAYMASTER_URL=your_paymaster_url
Create Nexus Client
import { createNexusClient, createBicoPaymasterClient } from "@biconomy/abstractjs";
import { baseSepolia } from "wagmi/chains";
import { http, useAccount, useWalletClient } from "wagmi";
const account = useAccount();
const { data: walletClient } = useWalletClient({ account: account.address });
async function initNexusClient() {
if (walletClient) {
const nexusClient = await createNexusClient({
signer: walletClient,
chain: baseSepolia, // or your preferred chain
paymaster: createBicoPaymasterClient({
paymasterUrl: process.env.NEXT_PUBLIC_PAYMASTER_URL || "",
}),
transport: http(),
bundlerTransport: http(process.env.NEXT_PUBLIC_BUNDLER_URL),
});
return nexusClient;
}
throw new Error("Wallet client not found");
}
Register a New Passkey
import {
toWebAuthnKey,
toPasskeyValidator,
WebAuthnMode,
} from "@biconomy/passkey";
import { NexusClient } from "@biconomy/abstractjs";
async function registerPasskey(nexusClient: NexusClient, passkeyName: string) {
// Create WebAuthn key
// Ideally "passkeyName" would be set by the user in the UI
const webAuthnKey = await toWebAuthnKey({
passkeyName: passkeyName,
mode: WebAuthnMode.Register,
});
// Create passkey validator
const passkeyValidator = await toPasskeyValidator({
account: nexusClient.account,
webAuthnKey,
});
// Store webAuthnKey for future use
const formattedWebAuthnKey = {
pubX: webAuthnKey.pubX.toString(),
pubY: webAuthnKey.pubY.toString(),
authenticatorId: webAuthnKey.authenticatorId,
authenticatorIdHash: webAuthnKey.authenticatorIdHash,
};
localStorage.setItem("webAuthnKey", JSON.stringify(formattedWebAuthnKey));
return passkeyValidator;
}
Login with Existing Passkey
import { NexusClient } from "@biconomy/abstractjs";
import {
toWebAuthnKey,
WebAuthnMode,
toPasskeyValidator,
} from "@biconomy/passkey";
async function loginPasskey(nexusClient: NexusClient) {
const webAuthnKey = await toWebAuthnKey({
mode: WebAuthnMode.Login,
});
const passkeyValidator = await toPasskeyValidator({
account: nexusClient.account,
webAuthnKey,
});
return passkeyValidator;
}
Install Passkey Validator Module
import type { NexusClient, Module } from "@biconomy/abstractjs";
async function installPasskeyValidator(
nexusClient: NexusClient,
passkeyValidator: Module
) {
const passkeyValidatorAddress = "0xD990393C670dCcE8b4d8F858FB98c9912dBFAa06";
const userOpHash = await nexusClient?.installModule({
module: {
address: passkeyValidatorAddress,
type: "validator",
initData: passkeyValidator?.initData,
},
});
// Wait for transaction to be confirmed
await nexusClient?.waitForUserOperationReceipt({ hash: userOpHash });
}
Using Passkey for Transactions
import {
createNexusClient,
createBicoPaymasterClient,
type Module,
type NexusClient,
moduleActivator,
} from "@biconomy/abstractjs";
import { baseSepolia } from "wagmi/chains";
import { http, useAccount, useWalletClient } from "wagmi";
import type { Address } from "viem";
const account = useAccount();
const { data: walletClient } = useWalletClient({ account: account.address });
async function sendTransactionWithPasskey(
nexusClient: NexusClient,
passkeyValidator: Module,
recipientAddress: Address
) {
// Extend NexusClient with passkey validator
nexusClient.extend(moduleActivator(passkeyValidator));
// Send transaction
const hash = await nexusClient.sendTransaction({
calls: [
{
to: recipientAddress,
value: BigInt(0), // or your desired value
},
],
});
// Wait for confirmation
const receipt = await nexusClient.waitForTransactionReceipt({ hash });
return receipt;
}
Uninstall Passkey Validator (Optional)
import {
type NexusClient,
type Module,
createNexusClient,
moduleActivator,
} from "@biconomy/abstractjs";
async function uninstallPasskeyValidator(
nexusClient: NexusClient,
passkeyValidator: Module
) {
nexusClient.extend(moduleActivator(passkeyValidator));
const userOpHash = await nexusClient?.uninstallModule({
module: {
address: passkeyValidator.address,
type: "validator",
deInitData: "0x",
},
});
await nexusClient?.waitForUserOperationReceipt({ hash: userOpHash });
// Clear stored passkey data
localStorage.removeItem("webAuthnKey");
}