How to use aggregate verifier in Web3Auth SFA JS SDK
This guide will cover the basics of how to set up your Web3Auth SDK, Auth0 and Google account for the integration and provide you with the links on how to develop a basic web application on the blockchain of your choice.
Quick Start
npx degit Web3Auth/web3auth-core-kit-examples/single-factor-auth-web/sfa-web-aggregate-verifier-example sfa-web-aggregate-verifier-demo && cd sfa-web-aggregate-verifier-demo && npm install && npm run start
How it works?
Single Factor Auth SDKs allow for the integration of a single factor of authentication, such as social login, into your dApp. They are designed to be simple to use and can be integrated into your dApp with minimal effort, allowing you to directly use the Web3Auth Network for Wallet Management. This is one of the most common use cases of Web3Auth, however, it is semi-custodial in nature, since the key is custodial to the Auth Provider and the Web3Auth Network.
- The first step for the application is to get the user authenticated by a login provider(here,
Google) and get the user's
idToken
. - Once the social login is successful, depending on whether the user has enabled Multi-Factor Authentication(MFA) or not, the key is generated.
- If the user has not enabled MFA, we use the
@web3auth/single-factor-auth
SDK to retrieve the private key shares from the Web3Auth auth network nodes and reconstruct the private key. - If the user has enabled MFA, an error message is shown that the user has enabled MFA and in this case, they should be using the Web3Auth Plug and Play Web SDKs.
Prerequisites
-
For Web Apps: A basic knowledge of JavaScript is required to use Web3Auth SDK.
-
For Mobile Apps: For the Web3Auth Mobile SDKs, you have a choice between iOS, Android, React Native & Flutter. Please refer to the Web3Auth SDK Reference for more information.
-
Create a Web3Auth account on the Web3Auth Dashboard
-
Create an Auth0 tenant and configure a Single Page Web Application (SPA for Web) or Native (for Mobile) from Auth0 Console.
-
Please note that Regular Web Applications are also supported as mentioned in the flows above. However, for this guide, we prefer SPA since its implicit flow doesn’t require an application to host a backend server.
Setup your Auth0 Tenant
-
Add the following URLs for your app to the Allowed Web Origins field when configuring your Auth0 Application.
- Additional to your URLs for the application, please add
-
You will require the
domain
andclientId
of the newly created application which you can copy from Auth0 Console.
Enable Social Login
- Enable
Google
or other social provider on theAuthentication > Social
page of your Auth0 Dashboard. - Visit https://auth0.com/learn/social-login to learn more.
Enable SMS Passwordless
If you want to implement SMS Passwordless, then this section is for you. Otherwise, you can skip this.
- Enable
SMS
on theAuthentication > Passwordless
page of your Auth0 Dashboard. - Under the
Settings
tab, add yourTwilio SID
andTwilio AuthToken
. - Also, update the
From
number on the same page, and click on theSave
button. - Next, enable your application under the
Applications
tab, and click on theSave
button. - You can test sending an SMS from the
Try
tab. Once, an SMS comes with OTP, it means it has been successfully configured.
Update Lockscreen for SMS Passwordless
If you're to use SMS Passwordless, please visit here to set up the Lock Screen of Auth0 from your Auth0 Dashboard.
Enable Email Passwordless
If you want to implement Email Passwordless, then this section is for you. Otherwise, you can skip this.
- Enable
Email
on theAuthentication > Passwordless
page of your Auth0 Dashboard. - Under the
Settings
tab, updateFrom
andSubject
based on your need and click on theSave
button. - Next, enable your application under the
Applications
tab, and click on theSave
button. - You can test sending an Email from the
Try
tab. Once, an Email comes with OTP/Link, it means it has been successfully configured.
Update Lockscreen for Email Passwordless
If you're to use Email Passwordless, please visit here to set up the Lock Screen of Auth0 from your Auth0 Dashboard.
Setup your Google App
-
Follow Google’s instructions to set up an OAuth 2.0 app.
-
Paste the following as a Redirect URI into the "Authorized redirect URIs" field.
-
Obtain the OAuth
Client ID
from your App on the Google Developer dashboard
Setup your Web3Auth Dashboard
-
Create a Project from the Project Section of the Web3Auth Developer Dashboard.
-
Enter your desired Project name.
-
Select the Product you want to use. For this guide, we'll be using the Plug n Play product.
-
Select the Platform type you want to use. For this guide, we'll be using the Web Application as the platform.
-
Select the Web3Auth Network as
Sapphire Devnet
. We recommend creating a project in thesapphire_devnet
network during development. While moving to a production environment, make sure to convert your project tosapphire_mainnet
or any of the legacy mainnet networkmainnet
,aqua
, orcyan
network. Otherwise, you'll end up losing users and keys. -
Select the blockchain(s) you'll be building this project on. For interoperability with Torus Wallets, you have the option of allowing the user's private key to be used in other applications using Torus Wallets (EVM, Solana, XRPL & Casper).
-
Finally, once you create the project, you have the option to whitelist your URLs for the project. Please whitelist the domains where your project will be hosted.
-
Create Auth0 Verifiers
-
Create a Verifier from the Custom Auth Section of the Developer Dashboard with the following configuration:
-
Pick a name of your choice for the verifier identifier.
eg. auth0-project
-
Choose
Social Login Providers
and selectAuth0
from the Login Provider dropdown. -
Next, Choose your Authentication Type from
eg. Google, Twitter, GitHub etc..
to be the Auth provider. -
Paste the
Client ID
andAuth0 Domain
from the Auth0 SPA you created in the above steps. This will be used to validate the JWT token issued by Auth0. And, selectSub
orEmail
as the JWT Verifier ID. -
Click on the
Create Verifier
button to create your verifier. It may take up to 10-20 minutes to deploy the verifier on Sapphire Devnet. You'll receive an email once it's complete.
You will require the
verifierName
of the newly created verifier andclientId
of the Plug and Play Project. -
Create SMS Passwordless Verifier
If you want to implement SMS Passwordless, then this section is for you. Otherwise, you can skip this.
-
Create a Verifier from the Custom Auth Section of the Developer Dashboard with the following configuration:
-
Choose a name of your choice for the verifier identifier.
eg. auth0-sms-passwordless
-
Select
Custom Providers
from the Login Provider. -
Choose
Custom
for theJWT Verifier ID
and typename
. -
Enter
https://{YOUR-DOMAIN}/.well-known/jwks.json
as yourJWKS Endpoint
. This will be used to validate the JWT token issued by Auth0. eg.https://web3auth.eu.auth0.com/.well-known/jwks.json
-
JWT validation fields:
- iss:
https://{YOUR-DOMAIN}
- aud:
{AUTH0-CLIENT-ID}
- iss:
-
Click on the
Create
button to create your verifier. It may take up to 10-20 minutes to deploy the verifier on Sapphire Devnet. You'll receive an email once it's complete.
You will require the
verifierName
of the newly created verifier andclientId
of the Plug and Play Project. -
Create Email Passwordless Verifier
If you want to implement Email Passwordless, then this section is for you. Otherwise, you can skip this.
-
Create a Verifier from the Custom Auth Section of the Developer Dashboard with the following configuration:
-
Choose a name of your choice for the verifier identifier.
eg. auth0-email-passwordless
-
Choose
Social Login Providers
and selectAuth0
from the Login Provider dropdown. -
Choose your Authentication Type as
Email Passwordless
to use Auth0's Email Passwordless. -
Paste the
Client ID
andAuth0 Domain
from the Auth0 SPA you created in the above steps. This will be used to validate the JWT token issued by Auth0. -
Click on the
Create
button to create your verifier. It may take up to 10-20 minutes to deploy the verifier on Sapphire Devnet. You'll receive an email once it's complete.
You will require the
verifierName
of the newly created verifier andclientId
of the Plug and Play Project. -
Using the Web3Auth SFA JS SDK
To use the Web3Auth SFA JS SDK, you need to add @web3auth/single-factor-auth
to your project.
Setting up your base project for using Web3 libraries:
If you are starting from scratch, to set up this project locally, you will need to create a base Web application, where you can install the required dependencies. However, while working with Web3, there are a few base libraries, which need additional configuration. This is because certain packages are not available in the browser environment, and we need to polyfill them manually. You can follow this documentation where we have mentioned the configuration changes for some popular frameworks for your reference.
Installation
For this project, you need to add the following Web3Auth dependencies to your package.json
npm install --save @web3auth/single-factor-auth @web3auth/ethereum-provider @web3auth/base web3 @auth0/auth0-react @react-oauth/google
Understanding the Dependencies
@web3auth/base
Since we're using typescript, we need the @web3auth/base
package to provide the types of the
different variables we'll be using throughout the app-building process. This reduces errors to a
very large extent.
npm install --save @web3auth/base
@web3auth/ethereum-provider
This package is used to provide the Ethereum provider to the Web3Auth SDK. This is required to interact with the blockchain.
npm install --save @web3auth/ethereum-provider
@web3auth/single-factor-auth
This package is the core package for Single Factor Auth JS SDK.
npm install --save @web3auth/single-factor-auth
@auth0/auth0-react
This package is used to provide the Auth0 SDK to the app. This is required to retrieve the idToken
from Auth0 as the login provider.
npm install --save @auth0/auth0-react
@react-oauth/google
This package is used to provide the Google SDK to the app. This is required to retrieve the
idToken
from Google as the login provider.
npm install --save @react-oauth/google
web3
This package is used to interact with the blockchain.
npm install --save web3
Wrapping component with GoogleOAuthProvider
and Auth0Provider
To use the Auth0 and Google SDK, we need to wrap our app with the GoogleOAuthProvider
and
Auth0Provider
components. This component provides the Google clientId
and the Auth0 domain
,
clientId
and authorizationParams
to the app.
import ReactDOM from "react-dom/client";
import App from "./App";
import { Auth0Provider } from "@auth0/auth0-react";
import { GoogleOAuthProvider } from "@react-oauth/google";
const root = ReactDOM.createRoot(document.getElementById("root") as HTMLElement);
root.render(
<GoogleOAuthProvider clientId="519228911939-cri01h55lsjbsia1k7ll6qpalrus75ps.apps.googleusercontent.com">
<Auth0Provider
domain="web3auth.au.auth0.com"
clientId="hiLqaop0amgzCC0AXo4w0rrG9abuJTdu"
authorizationParams={{
redirect_uri: window.location.origin,
connection: "github",
}}
>
<App />
</Auth0Provider>
</GoogleOAuthProvider>,
);
Initialization
Once installed, your Web3Auth application needs to be initialized. Initialization is a multi-step process where we add all the config details for Web3Auth SDK:
Importing the packages
import { Web3Auth } from "@web3auth/single-factor-auth";
import { CHAIN_NAMESPACES } from "@web3auth/base";
import { EthereumPrivateKeyProvider } from "@web3auth/ethereum-provider";
import { GoogleLogin, CredentialResponse, googleLogout } from "@react-oauth/google";
import { useAuth0 } from "@auth0/auth0-react";
Alongside the Web3Auth
and OpenloginAdapter
you need the above-mentioned packages from
@web3auth/base
for different initializations mentioned further in this guide.
Instantiate the Web3Auth SFA JS SDK
import { Web3Auth } from "@web3auth/single-factor-auth";
import { CHAIN_NAMESPACES } from "@web3auth/base";
import { EthereumPrivateKeyProvider } from "@web3auth/ethereum-provider";
import { GoogleLogin, CredentialResponse, googleLogout } from "@react-oauth/google";
import { useAuth0 } from "@auth0/auth0-react";
const clientId =
"BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ"; // get from https://dashboard.web3auth.io
const chainConfig = {
chainId: "0x1",
displayName: "Ethereum Mainnet",
chainNamespace: CHAIN_NAMESPACES.EIP155,
tickerName: "Ethereum",
ticker: "ETH",
decimals: 18,
rpcTarget: "https://rpc.ankr.com/eth",
blockExplorerUrl: "https://etherscan.io",
};
// Initialising Web3Auth Single Factor Auth SDK
const web3authSfa = new Web3Auth({
clientId, // Get your Client ID from Web3Auth Dashboard
web3AuthNetwork: "sapphire_mainnet", // Get your Network from Web3Auth Dashboard
usePnPKey: false, // Setting this to true returns the same key as PnP Web SDK, By default, this SDK returns CoreKitKey.
});
// Initializing Ethereum Provider
const privateKeyProvider = new EthereumPrivateKeyProvider({
config: { chainConfig },
});
Here, we're using the chainConfig
property to set the chainId
and chainNamespace
among other
parameters. The chainId
and chainNamespace
are the id and the namespace respectively of the
chain you're connecting to. We've initialized them for EVM for this guide. You can find the list of
available providers here to select from.
Additionally, sometimes you might face clogging in the network because the test network is a bit
clogged at that point. To avoid this, we can use the property rpcTarget
and pass over the URL of
the node you want to connect to.
Initializing the Web3Auth SDK
web3authSfa.init(privateKeyProvider);
Authentication
Getting the idToken
from Auth0 upon login and Web3Auth initialization
import { useAuth0 } from "@auth0/auth0-react";
const { getIdTokenClaims, loginWithPopup } = useAuth0();
await loginWithPopup();
const idToken = (await getIdTokenClaims())?.__raw.toString();
Parsing the token
We need to parse the token to get the email
field from the token. This is the unique identifier
for the user. This is dependent on the verifierId
field you've set on the dashboard. In our case,
it's email
. The code for parsing the idToken
is as follows:
import { safeatob } from "@toruslabs/openlogin-utils";
const parseToken = (token: any) => {
try {
const token = token.split(".")[1]; // payload
return JSON.parse(safeatob(token));
} catch (err) {
console.error(err);
return null;
}
};
const { email } = parseToken(idToken);
Now to initialize the Web3Auth SDK, we need to call the connect
method of the Web3Auth SDK.
const subVerifierInfoArray = [
{
verifier: "w3a-a0-github",
idToken: idToken!,
},
];
await web3authSfa.connect({
verifier,
verifierId: email,
idToken: idToken!,
subVerifierInfoArray,
});
Getting the idToken
and initializing Web3Auth
import { GoogleLogin, CredentialResponse, googleLogout } from "@react-oauth/google";
const onSuccess = async (response: CredentialResponse) => {
try {
const idToken = response.credential;
setIdToken(idToken!);
const { email } = parseToken(idToken);
console.log(email);
await web3authSfa.connect({
verifier: "w3a-google-demo",
verifierId: email,
idToken: idToken!,
});
} catch (err) {
// Single Factor Auth SDK throws an error if the user has already enabled MFA
// One can use the Web3AuthNoModal SDK to handle this case
setIsLoggingIn(false);
console.error(err);
}
};
Add this to your login page:
<GoogleLogin onSuccess={onSuccess} />
Initializing the Web3Auth SDK
The next step is to initialize the Web3Auth SDK. We now have all the parameters that are needed to
call the connect
method of the Web3Auth SDK.
await web3authSfa.connect({
verifier: "w3a-auth0-demo",
verifierId: sub,
idToken: idToken!,
});
Since we are directly using Single Factor Auth SDK to log in, the Web3Auth getUserInfo
function
won't work. We need to get the user details directly from the idToken
.
Get the User Profile
import { safeatob } from "@toruslabs/openlogin-utils";
const parseToken = (token: any) => {
try {
const token = token.split(".")[1]; // payload
return JSON.parse(safeatob(token));
} catch (err) {
console.error(err);
return null;
}
};
const userProfile = parseToken(idToken);
Logout
Logging out your user is as simple as calling the logout
function on the Web3Auth SDK.
await web3authSfa.logout();
await googleLogout();
Interacting with the Blockchain
So if you have completed this far, it means that you have successfully authenticated your user. Now,
you can use the provider returned by Web3Auth as web3auth.provider
to interact with your
blockchain. You can use the Provider SDKs to perform RPC Calls to your
blockchain.
Web3Auth is chain agnostic, ie. depending on whatever blockchain or layer-2 you use, Web3Auth can
easily support that. Web3Auth has native providers for EVM and Solana blockchains and for others,
you can get the private key in the user scope and make RPC calls. For standardising the type of
provider, Web3Auth Base provides a IProvider
from which you can create your own provider.
- Ethereum Provider gives you the capability of making RPC calls to the EVM compatible blockchains.
- Solana Provider gives you the capability of making RPC calls to the Solana blockchain.
- XRPL Provider gives you the capability of making RPC calls to the XRPL blockchain.
- If you want to use any other chain except Solana or EVM chains, for ex: Starknet, you can specify
the value of
chainNamespace
field as other in the Web3Auth SDK Constructor. Refer to: Using other blockchains
Get User Accounts
- Web3
- Ethers.js
const getAccounts = async () => {
if (!provider) {
console.log("provider not initialized yet");
return;
}
const web3 = new Web3(provider as any);
const userAccounts = await web3.eth.getAccounts();
console.log(userAccounts);
};
const getAccounts = async () => {
if (!provider) {
console.log("provider not initialized yet");
return;
}
// For ethers v5
// const ethersProvider = new ethers.providers.Web3Provider(this.provider);
const ethersProvider = new ethers.BrowserProvider(this.provider);
// For ethers v5
// const signer = ethersProvider.getSigner();
const signer = await ethersProvider.getSigner();
// Get the user's Ethereum public address
const address = signer.getAddress();
console.log(address);
};
View User Balance
- Web3
- Ethers.js
const getBalance = async () => {
if (!provider) {
console.log("provider not initialized yet");
return;
}
const web3 = new Web3(provider as any);
const accounts = await web3.eth.getAccounts();
const balance = await web3.eth.getBalance(accounts[0]);
console.log(web3.utils.fromWei(balance));
};
const getBalance = async () => {
if (!provider) {
console.log("provider not initialized yet");
return;
}
// For ethers v5
// const ethersProvider = new ethers.providers.Web3Provider(this.provider);
const ethersProvider = new ethers.BrowserProvider(this.provider);
// For ethers v5
// const signer = ethersProvider.getSigner();
const signer = await ethersProvider.getSigner();
// Get the user's Ethereum public address
const address = signer.getAddress();
// Get the user's balance in ether
// For ethers v5
// const balance = ethers.utils.formatEther(
// await ethersProvider.getBalance(address) // Balance is in wei
// );
const balance = ethers.formatEther(
await ethersProvider.getBalance(address), // Balance is in wei
);
console.log(balance);
};
Sign Message
- Web3
- Ethers.js
const signMessage = async () => {
if (!provider) {
console.log("provider not initialized yet");
return;
}
const web3 = new Web3(provider as any);
// Get user's Ethereum public address
const account = (await web3.eth.getAccounts())[0];
// Message
const message = "Hello MPC, Bye Bye SeedPhrase";
const typedMessage = [
{
type: "string",
name: "message",
value: message,
},
];
const params = [JSON.stringify(typedMessage), account];
const method = "eth_signTypedData";
const signedMessage = await this.provider.request({
method,
params,
});
console.log(signedMessage);
};
const signMessage = async () => {
if (!provider) {
console.log("provider not initialized yet");
return;
}
// For ethers v5
// const ethersProvider = new ethers.providers.Web3Provider(this.provider);
const ethersProvider = new ethers.BrowserProvider(this.provider);
// For ethers v5
// const signer = ethersProvider.getSigner();
const signer = await ethersProvider.getSigner();
const originalMessage = "YOUR_MESSAGE";
// Sign the message
const signedMessage = await signer.signMessage(originalMessage);
console.log(signedMessage);
};
Sign Transaction
const signTransaction = async () => {
if (!provider) {
console.log("provider not initialized yet");
return;
}
const web3 = new Web3(provider as any);
const accounts = await web3.eth.getAccounts();
const txRes = await web3.eth.signTransaction({
from: accounts[0],
to: accounts[0],
value: web3.utils.toWei("0.0001"),
chainId: 1, // change it to your specific chain id.
});
console.log(txRes.transactionHash);
};
Send Transaction
- Web3
- Ethers.js
const sendTransaction = async () => {
if (!provider) {
console.log("provider not initialized yet");
return;
}
const web3 = new Web3(provider as any);
const accounts = await web3.eth.getAccounts();
const txRes = await web3.eth.sendTransaction({
from: accounts[0],
to: accounts[0],
value: web3.utils.toWei("0.0001"),
chainId: 1, // change it to your specific chain id.
});
console.log(txRes.transactionHash);
};
const sendTransaction = async () => {
if (!provider) {
console.log("provider not initialized yet");
return;
}
// For ethers v5
// const ethersProvider = new ethers.providers.Web3Provider(this.provider);
const ethersProvider = new ethers.BrowserProvider(this.provider);
// For ethers v5
// const signer = ethersProvider.getSigner();
const signer = await ethersProvider.getSigner();
const destination = "0x40e1c367Eca34250cAF1bc8330E9EddfD403fC56";
// Convert 1 ether to wei
// For ethers v5
// const amount = ethers.utils.parseEther("0.001");
const amount = ethers.parseEther("0.001");
// Submit transaction to the blockchain
const tx = await signer.sendTransaction({
to: destination,
value: amount,
maxPriorityFeePerGas: "5000000000", // Max priority fee per gas
maxFeePerGas: "6000000000000", // Max fee per gas
});
// Wait for the transaction to be mined
const receipt = await tx.wait();
console.log(receipt.transactionHash);
};
Example Code
The code for the example can be found here.
Questions?
Ask us on Web3Auth Community Portal.