> ## Documentation Index
> Fetch the complete documentation index at: https://developers.circle.com/llms.txt
> Use this file to discover all available pages before exploring further.

# How-to: Set up passkey recovery

> Register a recovery key for a modular wallet so users can restore access to their MSCA if they lose their primary passkey.

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)](/wallets/account-types#externally-owned-accounts-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.

<Info>
  For a complete working app, see the [Passkey Recovery
  example](https://github.com/circlefin/modularwallets-web-sdk/tree/master/examples/passkey-recovery)
  in the modular wallets web SDK repository.
</Info>

## Before you begin

Before you begin, ensure that you've:

* [Created a modular wallet](/wallets/modular/create-a-modular-wallet) and have
  access to the `smartAccount`, `bundlerClient`, `client`, `modularTransport`,
  and `passkeyTransport` from that tutorial.
* Installed [`viem`](https://viem.sh/) for mnemonic and EOA generation.

## Steps

<Steps>
  <Step title="Register a recovery key">
    <Warning>
      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.
    </Warning>

    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](/wallets/gas-station) policy.
    * Call `estimateRegisterRecoveryAddressGas` first to surface the cost to the
      user instead of sponsoring it.

    ```typescript Web SDK (TypeScript) theme={null}
    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.
  </Step>

  <Step title="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.

    ```typescript Web SDK (TypeScript) theme={null}
    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.

    <Note>
      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.
    </Note>
  </Step>
</Steps>

## 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.
