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
_10yarn add @safe-global/auth-kit @web3auth/safeauth-embed
Imports
Here are all the necessary imports for this guide.
_10import { ethers } from 'ethers'_10import {_10 SafeAuthPack,_10 SafeAuthConfig,_10 SafeAuthInitOptions,_10} from '@safe-global/auth-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
_18const safeAuthConfig: SafeAuthConfig = {_18 txServiceUrl: 'https://safe-transaction-mainnet.safe.global',_18}_18const safeAuthInitOptions: SafeAuthInitOptions = {_18 enableLogging: true,_18 showWidgetButton: false,_18 chainConfig: {_18 chainId: '0x1',_18 rpcTarget: RPC_URL_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// }_18const safeAuthPack = new SafeAuthPack(safeAuthConfig)_18await 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._10const authKitSignData = await safeAuthPack.signIn()
The returned authKitSignData
data contains the following properties:
_10AuthKitSignInData {_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.
_10await safeAuthPack.signOut()
After the user is authenticated, call getProvider()
to get an Ethereum EIP-1193 (opens in a new tab) compatible provider.
_10safeAuthPack.getProvider()
We offer two methods for listening to events, subscribe()
and unsubscribe()
.
_10const accountChangedHandler = (accounts: string[]) => {_10 console.log('Signer accounts:', accounts)_10}_10_10safeAuthPack.subscribe('accountsChanged', accountChangedHandler)_10safeAuthPack.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.
_10const safeAuthPack = new SafeAuthPack()
Sign and execute transactions
The SafeAuthPack
can be used with the Protocol Kit to establish a connection to a Safe using the provider
. We don't need to pass the signer
property in the create()
method as it will be automatically taken from the passed provider
.
After connecting, you can use any of the methods provided in the Protocol Kit.
_23// Instantiate the Protocol Kit_23const protocolKit = await Safe.init({_23 provider: safeAuthPack.getProvider(),_23 safeAddress,_23})_23_23// Create a Safe transaction with the provided parameters_23const safeTransactionData: MetaTransactionData = {_23 to: `${ethAddress}`,_23 data: '0x',_23 value: ethers.parseUnits('0.0001', 'ether').toString(),_23}_23_23const safeTransaction = await protocolKit.createTransaction({_23 transactions: [safeTransactionData],_23})_23_23// Sign the transaction if the Safe have several owners_23// safeTransaction = await protocolKit1.signTransaction(safeTransaction)_23// safeTransaction = await protocolKit2.signTransaction(safeTransaction)_23_23// Execute the transaction_23await 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_16const web3 = new Web3(safeAuthPack.getProvider())_16_16await web3.eth.sendTransaction(tx)_16await web3.eth.signTransaction(tx)_16const message = 'hello world'_16const address = '0x...'_16await web3.eth.personal.sign(message, address)_16_16// Using ethers_16const provider = new ethers.BrowserProvider(safeAuthPack.getProvider())_16const signer = provider.getSigner()_16_16await signer.sendTransaction(tx)_16await signer.signTransaction(tx)_16await signer.signMessage(message)