How to create 2 factor authentication

Require two approvals before any important transaction.

Overview Sometimes you’ll want to add an extra layer of security and you’ll turn

on 2 factor authentication. FunWallets allow you to go even further and add more than just 2 steps – you can have 3, 4, or 5 steps if you want.

In this guide, I’ll show you how to set up 3 factor authentication using private keys. You can change the number of steps based on what works best for you. Also I recommend that you walk through the Quick Start since it will be useful as a reference point during some of the trickier steps.

Import required objects

We have to import three objects in order to create a FunWallet.

  1. FunWallet to create the object.

  2. configureEnvironment to set up the environment for a FunWallet.

  3. Auth for authenticating into a FunWallet.

import {
} from "@funkit/core";

Configuring the FunWallet environment

To begin, we need to set up the environment for your FunWallet. This is usually boilerplate code, but I will show you the process so that you can make adjustments in the future.

Let me explain the environment variables that we will need to input.

  1. chain - Each FunWallet exists on an EVM-compatible blockchain, and for this guide, we will be using the Goerli testnet.

  2. gasSponsor - All wallets have to pay gas to execute transactions on a blockchain and FunWallets are no exception to that. But FunWallets also have the option of a gas sponsor that can cover the gas cost. For this guide, we will use a gasless sponsor that is specified by sponsorAddress.

  3. apiKey - We have provided a rate limited apiKey used strictly for demoing purposes. Please visit our dashboard to receive your own production apiKey.

It is important to note that the use of a gasSponsor is tied to your apiKey.

await configureEnvironment({
chain: "goerli",
gasSponsor: {
sponsorAddress: "0x175C5611402815Eba550Dad16abd2ac366a63329",
apiKey: "ZrhepzWGxm74D0sqstuhT6dGrJxhoy8SZIToX6I3",

Creating Auth with private keys

Now that we’ve set up the environment, we need a way to sign transactions. All authentication in FunKit is handled with the Auth object.

We’ll use a private key as the authentication method and since we’re creating a 3 factor auth scheme (3FA) I’ll provide us with three. I’ll provide us with one. A private key for Ethereum consists of a 256-bit integer, and there are multiple methods for generating one.

const PRIVATE_KEY1 = generatePrivateKey();
const PRIVATE_KEY2 = generatePrivateKey();
const PRIVATE_KEY3 = generatePrivateKey();
const auth1 = new Auth({ privateKey: PRIVATE_KEY1 });
const auth2 = new Auth({ privateKey: PRIVATE_KEY2 });
const auth3 = new Auth({ privateKey: PRIVATE_KEY3 });

Checkout the WebSDK for additional 2FA methods.

Initializing FunWallet with Auth

With the Auth instances that we created in the step before, we are now able to initialize your FunWallet. Creating 3FA in FunWallet is the same as creating a group of three auth methods. Let’s step through each of the FunWallet constructor parameters we need to fill in.

  1. userId This is a unique identifier that we use to generate a user of FunWallet.

  2. groupInfo This is the most important parameter in this entire how to guide. Lets break down creating this group slowly.

  3. memberIds We’re going to pass in the three Auth addresses that we generated before as an array to create three members.

  4. threshold This is the parameter that determines how many members in the group are required in order to execute a transactions.

    • If we set it to three, it will require all three members in the group to sign in order to execute a transaction.

    • If we set it to two, it will require any two members in the group to sign in order to execute a transaction.

  5. uniqueId This is a random seed that is generated from our Auth instance. The purpose of this seed is to generate the address of our FunWallet.

const groupId = generateRandomGroupId();
const funWallet = new FunWallet({
users: [
userId: groupId,
groupInfo: {
memberIds: [
await auth1.getAddress(),
await auth2.getAddress(),
await auth3.getAddress(),
threshold: 3,
uniqueId: await auth1.getWalletUniqueId(Math.random()),

Execute transaction with three authenticators

The final step is to create the FunWallet on the Goerli testnet to deploy your FunWallet . All three authenticators will need to sign the operation in order for the transaction to be executed.

const createWalletOp = await funWallet.create(auth1, groupId);
const signedCreateWalletOp = await funWallet.signOperation(
const receipt = await funWallet.executeOperation(auth3, signedCreateWalletOp);


Putting together all the pieces we have multiFactorWalletCreation() that you can use to create your FunWallet.

import { FunWallet, Auth, configureEnvironment, GlobalEnvOption, generateRandomGroupId, generatePrivateKey } from "@funkit/core"
// Import keys
const PRIVATE_KEY1 = generatePrivateKey()
const PRIVATE_KEY2 = generatePrivateKey()
const PRIVATE_KEY3 = generatePrivateKey()
const API_KEY = "ZrhepzWGxm74D0sqstuhT6dGrJxhoy8SZIToX6I3"
// Configure environment options
const options: GlobalEnvOption = {
chain: "goerli",
gasSponsor: {
sponsorAddress: "0xCB5D0b4569A39C217c243a436AC3feEe5dFeb9Ad"
apiKey: API_KEY
const multiFactorWalletCreation = async () => {
await configureEnvironment(options)
const auth1 = new Auth({ privateKey: PRIVATE_KEY1 })
const auth2 = new Auth({ privateKey: PRIVATE_KEY2 })
const auth3 = new Auth({ privateKey: PRIVATE_KEY3 })
const groupId = generateRandomGroupId()
const funWallet = new FunWallet({
users: [
userId: groupId,
groupInfo: {
memberIds: [await auth1.getAddress(), await auth2.getAddress(), await auth3.getAddress()],
threshold: 3
uniqueId: await auth1.getWalletUniqueId(Math.random())
const createWalletOp = await funWallet.create(auth1, groupId)
const signedCreateWalletOp = await funWallet.signOperation(auth2, createWalletOp)
const receipt = await funWallet.executeOperation(auth3, signedCreateWalletOp)