# Wallet Creation and Recovery

## Creating embedded wallets

To create wallets for your users as part of the login flow you need use one of the following methods of **embeddedWallet**:

* `configure`: will create the wallet if it does not exist (where `AccountTypeEnum.SMART_ACCOUNT` is default), otherwise it will recover the existing wallet.
* `create`: will always create a new wallet, of the specified type.
* `recover`: will recover the wallet given a specific account id. To get a list of account ids you can use `embeddedWallet.list()`.

The `configure` method accepts the following parameters:

```typescript
configure(params: {
  chainId?: number                    // Target chain ID
  recoveryParams: RecoveryParams      // Recovery configuration (required)
  chainType?: ChainTypeEnum           // 'EVM' | 'SVM' (default: EVM)
  accountType?: AccountTypeEnum       // 'Smart Account' | 'Externally Owned Account' | 'Delegated Account' (default: Smart Account)
}): Promise<EmbeddedAccount>
```

The `recoveryParams` parameter is required. `chainType` defaults to `EVM` and `accountType` defaults to `SMART_ACCOUNT`.

**Make sure to wait for the embedded state ready before using the embedded wallets. Learn more about [how to check the embedded state](/docs/products/embedded-wallet/javascript/use-openfort#waiting-for-ready).**

## Response type

All wallet creation and recovery methods return an `EmbeddedAccount`:

```typescript
interface EmbeddedAccount {
  id: string                           // Account identifier
  chainType: 'EVM' | 'SVM'             // Chain type (Ethereum or Solana)
  address: string                       // Wallet address
  createdAt?: number                    // Unix timestamp
  implementationType?: string           // Smart account implementation
  factoryAddress?: string               // Factory contract address
  implementationAddress?: string        // Implementation contract address
  salt?: string                         // Account salt
  accountType: AccountTypeEnum          // 'Smart Account' | 'Externally Owned Account' | 'Delegated Account'
  recoveryMethod?: RecoveryMethod       // 'automatic' | 'password' | 'passkey'
  recoveryMethodDetails?: {
    passkeyId?: string
    passkeyEnv?: {
      name?: string
      os?: string
      osVersion?: string
      device?: string
    }
  }
  chainId?: number                      // Chain ID for the account
  ownerAddress?: string                 // Owner address (for smart accounts)
}
```

## Decide a recovery method

Recovering the embedded wallet is needed when a user logs into a new device or when access to the embedded wallet is lost.

Openfort embedded wallets have three recovery modes: automatic recovery, password recovery, and passkey recovery. At a high-level, this setting modulates how the embedded wallet's recovery share is encrypted and stored.

```typescript
import { RecoveryMethod } from '@openfort/openfort-js';

// Recovery method options
RecoveryMethod.AUTOMATIC  // Encryption session recovery
RecoveryMethod.PASSWORD   // Password-based recovery
RecoveryMethod.PASSKEY    // WebAuthn passkey recovery
```

* **[Automatic recovery](#automatic-recovery)**: The recovery share is encrypted with a combination of project entropy and Openfort's entropy. When logging into a new device, users can immediately access their embedded wallet.

:::tip
Before configuring the automatic recovery, generate your project's **publishable and secret shield keys** and store the **encryption share**. Learn about the different API keys [here](/docs/configuration/api-keys#shield-secret-and-publishable-keys).
:::

* **[Password recovery](#password-recovery):** The recovery share is encrypted by **user-provided entropy**. When logging into a new device, users must enter in their password to recover the embedded wallet on the new device. Once the embedded wallet has been recovered on a device, users will not need to enter their password on that devices again.

* **[Passkey recovery](#passkey-recovery):** The recovery share is encrypted using WebAuthn passkeys. Users can recover their wallet using biometric authentication or security keys.

### Automatic recovery

**From your backend**, you should have an endpoint that generates an encryption session for the user. This endpoint should be protected and only accessible by the user who is requesting the encryption session (i.e. the user who is logging in).

:::tip
Learn how to set up this endpoint and request an encryption session in our [automatic recovery session guide](/docs/products/embedded-wallet/server/automatic-recovery-session).
:::

:::code-group
```tsx [ConfigureWallet.tsx]
import openfort from "./openfortConfig"
import { RecoveryMethod, ChainTypeEnum } from '@openfort/openfort-js';

async function configureWalletWithAutoRecovery() {
  // Fetch encryption session from your protected backend endpoint
  const encryptionSession = await getEncryptionSession();

  const account = await openfort.embeddedWallet.configure({
    chainType: ChainTypeEnum.EVM,
    recoveryParams: {
      recoveryMethod: RecoveryMethod.AUTOMATIC,
      encryptionSession: encryptionSession,
    },
  });

  console.log('Wallet configured:', account.address);
  return account;
}
```

```ts [encryptionSession.ts]
// Fetch encryption session from your protected backend
const getEncryptionSession = async (): Promise<string> => {
  const response = await fetch('/api/protected-create-encryption-session', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
  });
  const data = await response.json();
  return data.session;
};

export default getEncryptionSession;
```

```ts [openfortConfig.ts]
import { Openfort } from '@openfort/openfort-js';

const openfort = new Openfort({
  baseConfiguration: {
    publishableKey: "YOUR_OPENFORT_PUBLISHABLE_KEY",
  },
  shieldConfiguration: {
    shieldPublishableKey: "YOUR_SHIELD_PUBLISHABLE_KEY",
  },
});

export default openfort;
```
:::

***

### Password recovery

Require that users set a password when the wallet is created.
**Only the user** can decrypt the recovery share.
Openfort never sees the user's password.

:::code-group
```tsx [ConfigureWallet.tsx]
import openfort from "./openfortConfig"
import { RecoveryMethod, AccountTypeEnum, ChainTypeEnum } from '@openfort/openfort-js';

async function configureWalletWithPassword(password: string) {
  const account = await openfort.embeddedWallet.configure({
    chainType: ChainTypeEnum.EVM,
    recoveryParams: {
      recoveryMethod: RecoveryMethod.PASSWORD,
      password: password,
    },
  });

  console.log('Wallet configured:', account.address);
  return account;
}
```

```ts [openfortConfig.ts]
import { Openfort } from '@openfort/openfort-js';

const openfort = new Openfort({
  baseConfiguration: {
    publishableKey: "YOUR_OPENFORT_PUBLISHABLE_KEY",
  },
  shieldConfiguration: {
    shieldPublishableKey: "YOUR_SHIELD_PUBLISHABLE_KEY",
  },
});

export default openfort;
```
:::

***

### Passkey recovery

Use WebAuthn passkeys for secure, passwordless recovery. Users authenticate with biometrics (Face ID, Touch ID, fingerprint) and keys sync across devices via iCloud Keychain or Google Password Manager.

:::info[Configuration parameters]
When using passkey recovery, you can configure the following parameters in `shieldConfiguration`:

| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `shieldPublishableKey` | Yes | — | Your Shield publishable key |
| `passkeyRpId` | No | `window.location.hostname` | The Relying Party ID (your domain). **Must match your production domain.** |
| `passkeyRpName` | No | `'3 random words'` | The service name shown in the browser's passkey creation dialog |
| `passkeyDisplayName` | No | `'Openfort - Embedded Wallet'` | The credential name shown next to the passkey in the browser dialog. Helps users identify specific credentials when they have multiple passkeys. |
:::

:::warning[Domain-bound credentials]
WebAuthn credentials are bound to a specific domain (the Relying Party). Credentials created for your domain (e.g., `example.com`) only work on that domain and its subdomains—they cannot be used on other domains.

**This means users cannot use the same passkey wallet on other applications.**
:::

:::code-group
```tsx [ConfigureWallet.tsx]
import openfort from "./openfortConfig"
import { RecoveryMethod, ChainTypeEnum } from '@openfort/openfort-js';

async function configureWalletWithPasskey() {
  const account = await openfort.embeddedWallet.configure({
    chainType: ChainTypeEnum.EVM,
    recoveryParams: {
      recoveryMethod: RecoveryMethod.PASSKEY,
    },
  });

  console.log('Wallet configured:', account.address);
  return account;
}
```

```ts [openfortConfig.ts]
import { Openfort } from '@openfort/openfort-js';

const openfort = new Openfort({
  baseConfiguration: {
    publishableKey: "YOUR_OPENFORT_PUBLISHABLE_KEY",
  },
  shieldConfiguration: {
    shieldPublishableKey: "YOUR_SHIELD_PUBLISHABLE_KEY",
    // For production, set passkeyRpId to match your domain:
    passkeyRpId: "yourdomain.com",
    passkeyRpName: "Your App Name",
    passkeyDisplayName: "My Wallet",
  },
});

export default openfort;
```
:::

## Creating a new wallet

Use `create` to always create a new wallet of the specified type. Unlike `configure`, this will always create a new wallet even if one already exists.

:::info
For automatic recovery, you need an encryption session from your backend. See the [automatic recovery session guide](/docs/products/embedded-wallet/server/automatic-recovery-session) for setup instructions.
:::

:::code-group
```tsx [CreateWallet.tsx]
import openfort from "./openfortConfig"
import getEncryptionSession from "./encryptionSession"
import { RecoveryMethod, AccountTypeEnum, ChainTypeEnum } from '@openfort/openfort-js';

async function createNewWallet() {
  // Fetch encryption session from your protected backend endpoint
  const encryptionSession = await getEncryptionSession();

  const account = await openfort.embeddedWallet.create({
    chainType: ChainTypeEnum.EVM,
    accountType: AccountTypeEnum.SMART_ACCOUNT,
    recoveryParams: {
      recoveryMethod: RecoveryMethod.AUTOMATIC,
      encryptionSession: encryptionSession,
    },
  });

  console.log('New wallet created:', account.address);
  return account;
}
```

```ts [openfortConfig.ts]
import { Openfort } from '@openfort/openfort-js';

const openfort = new Openfort({
  baseConfiguration: {
    publishableKey: "YOUR_OPENFORT_PUBLISHABLE_KEY",
  },
  shieldConfiguration: {
    shieldPublishableKey: "YOUR_SHIELD_PUBLISHABLE_KEY",
  },
});

export default openfort;
```
:::

## Recovering an existing wallet

Use `recover` to recover a specific wallet by account ID. This is useful when you need to recover a specific wallet from a list of accounts.

:::info
For automatic recovery, you need an encryption session from your backend. See the [automatic recovery session guide](/docs/products/embedded-wallet/server/automatic-recovery-session) for setup instructions.
:::

:::code-group
```tsx [RecoverWallet.tsx]
import openfort from "./openfortConfig"
import getEncryptionSession from "./encryptionSession"
import { RecoveryMethod } from '@openfort/openfort-js';

async function recoverWallet(accountId: string) {
  // Fetch encryption session from your protected backend endpoint
  const encryptionSession = await getEncryptionSession();

  const account = await openfort.embeddedWallet.recover({
    account: accountId,
    recoveryParams: {
      recoveryMethod: RecoveryMethod.AUTOMATIC,
      encryptionSession: encryptionSession,
    },
  });

  console.log('Wallet recovered:', account.address);
  return account;
}

// List available accounts to recover
async function listAccounts() {
  const accounts = await openfort.embeddedWallet.list();
  console.log('Available accounts:', accounts);
  return accounts;
}

// List with optional filters
async function listFilteredAccounts() {
  const accounts = await openfort.embeddedWallet.list({
    accountType: AccountTypeEnum.SMART_ACCOUNT,
    chainType: ChainTypeEnum.EVM,
    chainId: 80002,
    order: 'desc',
    limit: 10,
    skip: 0,
  });
  return accounts;
}
```

```ts [openfortConfig.ts]
import { Openfort } from '@openfort/openfort-js';

const openfort = new Openfort({
  baseConfiguration: {
    publishableKey: "YOUR_OPENFORT_PUBLISHABLE_KEY",
  },
  shieldConfiguration: {
    shieldPublishableKey: "YOUR_SHIELD_PUBLISHABLE_KEY",
  },
});

export default openfort;
```
:::

## Get the current wallet

Use `get` to retrieve the currently configured embedded wallet:

```tsx
const currentAccount = await openfort.embeddedWallet.get();
console.log('Current wallet:', currentAccount.address);
```

## Wallet Pre-generation

Openfort also allows you to pre-generate embedded wallets for your users, even before they first login to your app. Please see our [pregeneration guide](/docs/products/embedded-wallet/server/pregenerate-wallets) for more.
