SDK
Guides
Safe Auth

Integration with SafeAuth

This guide demonstrates creating an externally-owned account using your email or social media account. Once authenticated, you can sign transactions and interact with your Safe accounts.

The SafeAuthPack is an authentication system that utilizes the Web3Auth (opens in a new tab) MPC technology. It was developed in collaboration with Web3Auth to create a smooth onboarding experience for web2 users across different dapps.

Prerequisites

Steps

Install dependencies


_10
yarn add @safe-global/auth-kit @web3auth/safeauth-embed

Imports

Here are all the necessary imports for this guide.


_10
import { ethers } from 'ethers'
_10
import {
_10
SafeAuthPack,
_10
SafeAuthConfig,
_10
SafeAuthInitOptions,
_10
} from '@safe-global/auth-kit'
_10
import { EthersAdapter } from '@safe-global/protocol-kit'

Create a SafeAuthPack instance

We will use the SafeAuthPack exported from the @safe-global/auth-kit package.

Create an instance of the SafeAuthPack (opens in a new tab) using the required SafeAuthConfig configuration object.

Supported networks:

  • Production: Ethereum, Polygon, BSC, Avalanche, Optimism, Celo, Arbitrum, Gnosis chain
  • Test: Sepolia, Polygon Mumbai, BSC Testnet, Avalanche Testnet, Arbitrum Testnet, Optimism Testnet

_18
const safeAuthConfig: SafeAuthConfig = {
_18
txServiceUrl: 'https://safe-transaction-mainnet.safe.global',
_18
}
_18
const safeAuthInitOptions: SafeAuthInitOptions = {
_18
enableLogging: true,
_18
showWidgetButton: false,
_18
chainConfig: {
_18
chainId: '0x1',
_18
rpcTarget: `${rpcUrl}`
_18
}
_18
}
_18
_18
// You can also pass the SafeAuthConfig as a parameter to the SafeAuthPack constructor if you are using a custom txServiceUrl domain
_18
// e.g. const safeAuthConfig: SafeAuthConfig = {
_18
// txServiceUrl: 'https://safe-transaction-mainnet.safe.global'
_18
// }
_18
const safeAuthPack = new SafeAuthPack(safeAuthConfig)
_18
await safeAuthPack.init(safeAuthInitOptions)

Sign in to an Ethereum account

After creating your SafeAuthPack instance, initiate the authentication process by calling the signIn() method. Typically, this method is called when the user clicks a "Sign In" button on the web page.

After successfully signing in, you will create a new Ethereum Wallet. This wallet will be used for all future logins and can be shared across different applications.


_10
// The signIn() method returns the user's Ethereum address and the associated Safe addresses
_10
// The `await` will last until the user is authenticated. Therefore, it will be active while the authentication popup is being displayed.
_10
const authKitSignData = await safeAuthPack.signIn()

The returned authKitSignData data contains the following properties:


_10
AuthKitSignInData {
_10
eoa: string // The safe signer
_10
safes?: string[] // The list of associated Safe addresses in the chain
_10
}

The signOut() method removes the current session.


_10
await safeAuthPack.signOut()

After the user is authenticated, call getProvider() to get the Ethereum provider instance. This is a EIP-1193 (opens in a new tab) compatible provider you can wrap using your favorite library (web3, ethers).


_10
safeAuthPack.getProvider()

We offer two methods for listening to events, subscribe() and unsubscribe().


_10
const accountChangedHandler = (accounts: string[]) => {
_10
console.log('Signer accounts:', accounts)
_10
}
_10
_10
safeAuthPack.subscribe('accountsChanged', accountChangedHandler)
_10
safeAuthPack.unsubscribe('accountsChanged', accountChangedHandler)

The SafeAuthPack instantiation will return the list of associated Safe addresses as part of the response from the signIn() method when the txServiceUrl is provided.


_10
const safeAuthPack = new SafeAuthPack()

Sign and execute transactions

The SafeAuthPack can be used with the Protocol Kit to establish a connection to a Safe. This connection is made using the provider and signer associated with the authenticated account.

After connecting, you can use any of the methods provided in the Protocol Kit (opens in a new tab).


_33
// Wrap EIP-1193 provider with ethers
_33
const provider = new ethers.BrowserProvider(safeAuthPack.getProvider())
_33
const signer = provider.getSigner()
_33
_33
// Create the Safe EthersAdapter
_33
const ethAdapter = new EthersAdapter({
_33
ethers,
_33
signerOrProvider: signer || provider,
_33
})
_33
_33
// Instantiate the Protocol Kit
_33
const protocolKit = await Safe.create({
_33
ethAdapter,
_33
safeAddress,
_33
})
_33
_33
// Create a Safe transaction with the provided parameters
_33
const safeTransactionData: MetaTransactionData = {
_33
to: `${ethAddress}`,
_33
data: '0x',
_33
value: ethers.parseUnits('0.0001', 'ether').toString(),
_33
}
_33
_33
const safeTransaction = await protocolKit.createTransaction({
_33
transactions: [safeTransactionData],
_33
})
_33
_33
// Sign the transaction if the Safe have several owners
_33
// safeTransaction = await protocolKit1.signTransaction(safeTransaction)
_33
// safeTransaction = await protocolKit2.signTransaction(safeTransaction)
_33
_33
// Execute the transaction
_33
await protocolKit.executeTransaction(safeTransaction)

Sign messages

You can also sign any arbitrary message or transaction as a regular Signing Account with your favorite web3 library:


_16
// Using web3
_16
const web3 = new Web3(safeAuthPack.getProvider())
_16
_16
await web3.eth.sendTransaction(tx)
_16
await web3.eth.signTransaction(tx)
_16
const message = 'hello world'
_16
const address = '0x...'
_16
await web3.eth.personal.sign(message, address)
_16
_16
// Using ethers
_16
const provider = new ethers.BrowserProvider(safeAuthPack.getProvider())
_16
const signer = provider.getSigner()
_16
_16
await signer.sendTransaction(tx)
_16
await signer.signTransaction(tx)
_16
await signer.signMessage(message)

Examples

Was this page helpful?