# Migrate from Web3Auth

This guide walks you through migrating from Web3Auth (now MetaMask Embedded Wallets) to Openfort. The migration involves updating your SDK dependencies, provider configuration, authentication flows, and wallet interactions.

:::warning
This migration generates new wallet addresses for your users. Users need to transfer any assets from their Web3Auth wallets to their new Openfort wallets after migration.
:::

## Before you begin

Before starting the migration:

1. Complete the [Openfort quickstart](/docs/products/embedded-wallet/react) to understand the SDK structure.
2. Obtain your [API keys](/docs/configuration/api-keys) from the Openfort dashboard.
3. Set up a [recovery endpoint](/docs/products/embedded-wallet/server/automatic-recovery-session) (for automatic recovery).

### Feature mapping

| Web3Auth feature | Openfort equivalent | Notes |
|------------------|---------------------|-------|
| Social login (Google, Facebook) | `AuthProvider.GOOGLE`, `AuthProvider.FACEBOOK` | Configure in dashboard |
| Email passwordless | `AuthProvider.EMAIL_OTP` | OTP-based authentication |
| SMS passwordless | `AuthProvider.PHONE` | OTP-based authentication |
| External wallets | `AuthProvider.WALLET` | WalletConnect support |
| MFA management | Passkey recovery | Alternative security model |
| Whitelabeling | `uiConfig` prop | Customizable UI |

::::steps

### Install Openfort dependencies

Remove Web3Auth packages and install Openfort with its peer dependencies:

:::code-group

```sh [npm]
npm uninstall @web3auth/modal
npm install @openfort/react wagmi viem@^2.22.0 @tanstack/react-query
```

```sh [yarn]
yarn remove @web3auth/modal
yarn add @openfort/react wagmi viem@^2.22.0 @tanstack/react-query
```

```sh [pnpm]
pnpm remove @web3auth/modal
pnpm add @openfort/react wagmi viem@^2.22.0 @tanstack/react-query
```

:::

### Update provider configuration

Replace the Web3Auth provider with Openfort's layered provider structure.

**Before (Web3Auth):**

```tsx [Providers.tsx (Web3Auth)]
import { Web3AuthProvider } from '@web3auth/modal/react';
import { WEB3AUTH_NETWORK } from '@web3auth/modal';

const web3AuthConfig = {
  clientId: 'YOUR_WEB3AUTH_CLIENT_ID',
  web3AuthNetwork: WEB3AUTH_NETWORK.SAPPHIRE_MAINNET,
  chainConfig: {
    chainNamespace: 'eip155',
    chainId: '0x1',
  },
};

function App() {
  return (
    <Web3AuthProvider config={web3AuthConfig}>
      <YourApp />
    </Web3AuthProvider>
  );
}
```

**After (Openfort):**

```tsx [Providers.tsx (Openfort)]
import {
  AuthProvider,
  OpenfortProvider,
  RecoveryMethod,
} from "@openfort/react";
import { getDefaultConfig, OpenfortWagmiBridge } from "@openfort/react/wagmi";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { WagmiProvider, createConfig } from "wagmi";
import { mainnet, sepolia } from "viem/chains";

const config = createConfig(
  getDefaultConfig({
    appName: "Your App Name",
    chains: [mainnet, sepolia],  // [!code highlight]
    ssr: true,
  })
);

const queryClient = new QueryClient();

function Providers({ children }: { children: React.ReactNode }) {
  return (
    <QueryClientProvider client={queryClient}>
      <WagmiProvider config={config}>
        <OpenfortWagmiBridge>
        <OpenfortProvider
          publishableKey="YOUR_OPENFORT_PUBLISHABLE_KEY"  // [!code highlight]
          walletConfig={{
            shieldPublishableKey: "YOUR_SHIELD_PUBLISHABLE_KEY",  // [!code highlight]
            createEncryptedSessionEndpoint: "YOUR_RECOVERY_ENDPOINT",  // [!code highlight]
          }}
          uiConfig={{
            authProviders: [
              AuthProvider.EMAIL_OTP,
              AuthProvider.GOOGLE,
              AuthProvider.WALLET,
            ],
            walletRecovery: {
              defaultMethod: RecoveryMethod.AUTOMATIC,
            },
          }}
        >
          {children}
        </OpenfortProvider>
        </OpenfortWagmiBridge>
      </WagmiProvider>
    </QueryClientProvider>
  );
}
```

### Update authentication code

Replace Web3Auth connection hooks with Openfort authentication hooks.

**Before (Web3Auth):**

```tsx [LoginButton.tsx (Web3Auth)]
import { useWeb3AuthConnect, useWeb3AuthDisconnect, useWeb3AuthUser } from '@web3auth/modal/react';
import { AUTH_CONNECTION, WALLET_CONNECTORS } from '@web3auth/modal';

function LoginButton() {
  const { isConnected, connectTo } = useWeb3AuthConnect();
  const { userInfo } = useWeb3AuthUser();
  const { disconnect } = useWeb3AuthDisconnect();

  if (isConnected) {
    return (
      <div>
        <p>Welcome, {userInfo?.email}</p>
        <button onClick={() => disconnect()}>Disconnect</button>
      </div>
    );
  }

  return (
    <button onClick={() => connectTo(WALLET_CONNECTORS.AUTH, {
      authConnection: AUTH_CONNECTION.GOOGLE,
    })}>
      Connect with Web3Auth
    </button>
  );
}
```

**After (Openfort):**

```tsx [LoginButton.tsx (Openfort)]
import { useUser, useSignOut, OpenfortButton } from "@openfort/react";

function LoginButton() {
  const { user, isLoading, isAuthenticated } = useUser();  // [!code highlight]
  const { signOut } = useSignOut();

  if (isLoading) return <div>Loading...</div>;  // [!code highlight]

  if (isAuthenticated) {
    return (
      <div>
        <p>Welcome, {user?.email}</p>
        <button onClick={signOut}>Sign Out</button>
      </div>
    );
  }

  // Use the pre-built button component  // [!code highlight]
  return <OpenfortButton />;  // [!code highlight]
}
```

Alternatively, use individual auth hooks for custom UI:

```tsx [CustomLogin.tsx]
import { useEmailOtpAuth, useOAuth, AuthProvider } from "@openfort/react";
import { useState } from "react";

function CustomLogin() {
  const { requestEmailOtp, signInEmailOtp, isRequesting, isLoading } = useEmailOtpAuth();  // [!code highlight]
  const { initOAuth } = useOAuth();
  const [email, setEmail] = useState("");
  const [otp, setOtp] = useState("");
  const [otpSent, setOtpSent] = useState(false);  // [!code highlight]

  const handleRequestOtp = async () => {
    await requestEmailOtp({ email });  // [!code highlight]
    setOtpSent(true);  // [!code highlight]
  };

  const handleSignIn = async () => {
    await signInEmailOtp({ email, otp });  // [!code highlight]
  };

  return (
    <div>
      <input
        value={email}
        onChange={(e) => setEmail(e.target.value)}
        placeholder="Email"
      />
      {otpSent && (
        <input
          value={otp}
          onChange={(e) => setOtp(e.target.value)}
          placeholder="Enter OTP"
        />
      )}
      {!otpSent ? (
        <button onClick={handleRequestOtp} disabled={isRequesting}>
          {isRequesting ? "Sending..." : "Send OTP"}
        </button>
      ) : (
        <button onClick={handleSignIn} disabled={isLoading}>
          {isLoading ? "Verifying..." : "Verify"}
        </button>
      )}
      <button onClick={() => initOAuth({ provider: AuthProvider.GOOGLE })}>
        Sign in with Google
      </button>
    </div>
  );
}
```

### Keep your wallet and transaction code

Both Web3Auth v10 and Openfort use Wagmi for blockchain interactions. Your existing Wagmi hooks for wallet access and transactions work without changes.

```tsx [WalletInfo.tsx]
import { useAccount } from "wagmi";

function WalletInfo() {
  const { address, isConnected } = useAccount();

  if (!isConnected) return null;

  return <p>Wallet: {address}</p>;  // Returns the smart wallet address with Openfort
}
```

```tsx [SendTransaction.tsx]
import { useSendTransaction, useAccount } from "wagmi";
import { parseEther } from "viem";

function SendTransaction() {
  const { address } = useAccount();
  const { sendTransaction, isPending } = useSendTransaction();

  const sendTx = () => {
    sendTransaction({
      to: '0x...',
      value: parseEther('0.001'),
    });
  };

  return (
    <button onClick={sendTx} disabled={isPending || !address}>
      {isPending ? 'Sending...' : 'Send'}
    </button>
  );
}
```

:::note
With Openfort, the address returned by `useAccount` is a smart contract wallet address. Transactions sent via `useSendTransaction` can be sponsored using [gas policies](/docs/configuration/gas-sponsorship), so your users don't need to hold native tokens.
:::

### Remove Web3Auth references

Remove any remaining Web3Auth imports and clean up unused code.

:::code-group

```sh [npm]
npm uninstall @web3auth/modal @web3auth/ethereum-provider
```

```sh [yarn]
yarn remove @web3auth/modal @web3auth/ethereum-provider
```

```sh [pnpm]
pnpm remove @web3auth/modal @web3auth/ethereum-provider
```

:::

::::

## Hook mapping reference

| Web3Auth hook | Openfort equivalent |
|---------------|---------------------|
| `useWeb3AuthConnect` | `useEmailOtpAuth`, `useOAuth`, `useGuestAuth` |
| `useWeb3AuthDisconnect` | `useSignOut` |
| `useWeb3AuthUser` | `useUser` |
| `useAccount` (wagmi) | `useAccount` (wagmi) |
| `useSendTransaction` (wagmi) | `useSendTransaction` (wagmi) |
| `useSwitchChain` (wagmi) | `useSwitchChain` (wagmi) |

## Considerations

### Session handling

Web3Auth sessions are invalidated during migration. Users need to re-authenticate with Openfort.

### Wallet addresses

Users receive new wallet addresses. Communicate this to users before migration so they can:

1. Export any assets from their Web3Auth wallet.
2. Import or transfer assets to their new Openfort wallet after migration.

### MFA and recovery

Web3Auth uses MPC-based key management. Openfort provides three recovery options:

* **Automatic recovery**: Backend-managed, seamless user experience.
* **Password recovery**: User sets a password for wallet recovery.
* **Passkey recovery**: Biometric authentication for recovery.

### Smart wallet features

Openfort wallets are smart contract accounts by default. You gain access to:

* Gas sponsorship via paymasters.
* Transaction batching.
* Session keys for delegated signing.

Configure gas policies in the [Openfort dashboard](https://dashboard.openfort.io).

## Next steps

<HoverCardLayout>
  <HoverCardLink description="Configure your embedded wallet settings." href="/products/embedded-wallet/react/wallet" title="Wallet configuration" subtitle="Wallet setup" icon={Wallet} color="#3B82F6" />

  <HoverCardLink description="Cover gas fees for your users." href="/configuration/gas-sponsorship" title="Gas sponsorship" subtitle="Paymaster setup" icon={Fuel} color="#10B981" />
</HoverCardLayout>
