Skip to content
LogoLogo

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.

Before you begin

Before starting the migration:

  1. Complete the Openfort quickstart to understand the SDK structure.
  2. Obtain your API keys from the Openfort dashboard.
  3. Set up a recovery endpoint (for automatic recovery).

Feature mapping

Web3Auth featureOpenfort equivalentNotes
Social login (Google, Facebook)AuthProvider.GOOGLE, AuthProvider.FACEBOOKConfigure in dashboard
Email passwordlessAuthProvider.EMAIL_OTPOTP-based authentication
SMS passwordlessAuthProvider.PHONEOTP-based authentication
External walletsAuthProvider.WALLETWalletConnect support
MFA managementPasskey recoveryAlternative security model
WhitelabelinguiConfig propCustomizable UI

Install Openfort dependencies

Remove Web3Auth packages and install Openfort with its peer dependencies:

Update provider configuration

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

Before (Web3Auth):

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):

Providers.tsx (Openfort)
import {
  AuthProvider,
  OpenfortProvider,
  getDefaultConfig,
  RecoveryMethod,
} from "@openfort/react";
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],  
    ssr: true,
  })
);
 
const queryClient = new QueryClient();
 
function Providers({ children }: { children: React.ReactNode }) {
  return (
    <WagmiProvider config={config}>
      <QueryClientProvider client={queryClient}>
        <OpenfortProvider
          publishableKey="YOUR_OPENFORT_PUBLISHABLE_KEY"
          walletConfig={{
            shieldPublishableKey: "YOUR_SHIELD_PUBLISHABLE_KEY",  
            createEncryptedSessionEndpoint: "YOUR_RECOVERY_ENDPOINT",  
          }}
          uiConfig={{
            authProviders: [
              AuthProvider.EMAIL_OTP,
              AuthProvider.GOOGLE,
              AuthProvider.WALLET,
            ],
            walletRecovery: {
              defaultMethod: RecoveryMethod.AUTOMATIC,
            },
          }}
        >
          {children}
        </OpenfortProvider>
      </QueryClientProvider>
    </WagmiProvider>
  );
}

Update authentication code

Replace Web3Auth connection hooks with Openfort authentication hooks.

Before (Web3Auth):

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):

LoginButton.tsx (Openfort)
import { useUser, useSignOut, OpenfortButton } from "@openfort/react";
 
function LoginButton() {
  const { user, isLoading } = useUser();
  const { signOut } = useSignOut();
 
  if (isLoading) return <div>Loading...</div>;
 
  if (user) {
    return (
      <div>
        <p>Welcome, {user.email}</p>
        <button onClick={signOut}>Sign Out</button>
      </div>
    );
  }
 
  // Use the pre-built button component
  return <OpenfortButton />;  
}

Alternatively, use individual auth hooks for custom UI:

CustomLogin.tsx
import { useEmailOtpAuth, useOAuth, AuthProvider } from "@openfort/react";
 
function CustomLogin() {
  const { sendOtp, verifyOtp, state } = useEmailOtpAuth();
  const { initOAuth } = useOAuth();
  const [email, setEmail] = useState("");
  const [otp, setOtp] = useState("");
 
  const handleEmailLogin = async () => {
    if (state === "initial") {
      await sendOtp({ email });
    } else if (state === "awaiting_otp") {
      await verifyOtp({ otp });
    }
  };
 
  return (
    <div>
      <input
        value={email}
        onChange={(e) => setEmail(e.target.value)}
        placeholder="Email"
      />
      {state === "awaiting_otp" && (
        <input
          value={otp}
          onChange={(e) => setOtp(e.target.value)}
          placeholder="Enter OTP"
        />
      )}
      <button onClick={handleEmailLogin}>
        {state === "initial" ? "Send OTP" : "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.

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
}
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>
  );
}

Remove Web3Auth references

Remove any remaining Web3Auth imports and clean up unused code.

Hook mapping reference

Web3Auth hookOpenfort equivalent
useWeb3AuthConnectuseEmailOtpAuth, useOAuth, useGuestAuth
useWeb3AuthDisconnectuseSignOut
useWeb3AuthUseruseUser
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.

Next steps

Wallet configuration
Wallet configuration
Wallet setup
Configure your embedded wallet settings.
Gas sponsorship
Gas sponsorship
Paymaster setup
Cover gas fees for your users.