Skip to main content
Passkeys live on a user’s device. If the device is lost or the passkey is deleted, the user can’t sign for their MSCA anymore. Passkey recovery solves this by adding a second signer to the MSCA, an externally owned account (EOA) controlled by a mnemonic the user stores securely. The EOA is the backup signer. If the user ever loses their passkey, they can sign with the recovery EOA to register a new passkey on the same MSCA.
For a complete working app, see the Passkey Recovery example in the modular wallets web SDK repository.

Before you begin

Before you begin, ensure that you’ve:
  • Created a modular wallet and have access to the smartAccount, bundlerClient, client, modularTransport, and passkeyTransport from that tutorial.
  • Installed viem for mnemonic and EOA generation.

Steps

1

Register a recovery key

Register the recovery key while the user still has their original passkey. If both the passkey and the recovery mnemonic are lost, the wallet is permanently inaccessible.
Generate a recovery mnemonic, derive an EOA from it, and register the EOA’s address as a signer on the MSCA. Extend the bundler client with recoveryActions to expose the recovery methods.Gas options:
  • Pass paymaster: true to sponsor gas through your Gas Station policy.
  • Call estimateRegisterRecoveryAddressGas first to surface the cost to the user instead of sponsoring it.
Web SDK (TypeScript)
import { english, generateMnemonic, mnemonicToAccount } from "viem/accounts";
import { recoveryActions } from "@circle-fin/modular-wallets-core";

const recoveryClient = bundlerClient.extend(recoveryActions);

const mnemonic = generateMnemonic(english);
const recoveryEoa = mnemonicToAccount(mnemonic);

await recoveryClient.registerRecoveryAddress({
  account: smartAccount,
  recoveryAddress: recoveryEoa.address,
  paymaster: true,
});
registerRecoveryAddress submits a user operation and resolves once it lands. The recovery EOA is now a signer on the MSCA.The mnemonic is the only credential the user needs to recover later. Prompt them to store it somewhere safe (a password manager, hardware wallet, or written backup) before continuing.
2

Recover access after passkey loss

When the original passkey is gone, take the user’s recovery mnemonic and use it to add a new passkey to the same MSCA. The flow recreates the recovery EOA, registers a new passkey credential, binds that passkey to the original MSCA, and rebuilds the smart account using the new credential.
Web SDK (TypeScript)
import { mnemonicToAccount } from "viem/accounts";
import {
  createBundlerClient,
  toWebAuthnAccount,
} from "viem/account-abstraction";
import {
  recoveryActions,
  toCircleSmartAccount,
  toWebAuthnCredential,
  WebAuthnMode,
} from "@circle-fin/modular-wallets-core";

// Recreate the recovery EOA and a temporary smart account from it.
const localAccount = mnemonicToAccount(savedMnemonic);

const tempSmartAccount = await toCircleSmartAccount({
  client,
  owner: localAccount,
});

// Register a new passkey credential.
const newCredential = await toWebAuthnCredential({
  transport: passkeyTransport,
  mode: WebAuthnMode.Register,
  username: "recovery-passkey",
});

// Sign the recovery userOp with the temporary EOA account.
const recoveryClient = createBundlerClient({
  account: tempSmartAccount,
  chain,
  transport: modularTransport,
}).extend(recoveryActions);

// Bind the new passkey to the original MSCA.
await recoveryClient.executeRecovery({
  account: tempSmartAccount,
  credential: newCredential,
  paymaster: true,
});

// Rebuild the smart account using the new passkey.
const recoveredAccount = await toCircleSmartAccount({
  client,
  owner: toWebAuthnAccount({ credential: newCredential }),
});
The user can now sign with the new passkey.
Recovery adds the new passkey as an owner on the MSCA. It does not remove the original passkey. If the user still has the old credential on a device, both might be able to sign.

Best practices

  • Educate users. Make it explicit that losing both the passkey and the recovery mnemonic permanently locks the wallet. Encourage password managers or hardware backups.
  • Offer redundancy. The MSCA supports multiple recovery addresses. Letting users register more than one reduces single-point failure.
  • Test the recovery path. Walk through the full lose-and-recover flow on testnet across the browsers and devices you support before enabling recovery in production.
  • Revoke stolen passkeys separately. Recovery restores access, it does not invalidate the original passkey. If a passkey might have been stolen rather than lost, add a separate owner-removal flow to your security model.