Skip to main content

Using Server Side Verification with Web3Auth Plug and Play No Modal SDK

ethereumweb3auth coregooglenext.jsserver side verificationWeb3Auth Team | July 26, 2022

This guide will cover the basics of how to use Web3Auth's Server Side Verification to verify the idToken received in the web3auth.getUserInfo() method of Web3Auth.

Quick Start

npx degit Web3Auth/web3auth-pnp-examples/web-no-modal-sdk/server-side-verification-no-modal-example w3a-ssv-demo && cd w3a-ssv-demo && npm install && npm run dev

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

  • A Google Developer account to be used as Login provider for Web3Auth Custom Authentication.

Setup

Setup your Google App

  1. Follow Google’s instructions to set up an OAuth 2.0 app.

  2. Paste the following as a Redirect URI into the "Authorized redirect URIs" field.

    Google OAuth2.0 App Dashboard

  3. 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.

    Plug n Play Project Creation on Web3Auth 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 the sapphire_devnet network during development. While moving to a production environment, make sure to convert your project to sapphire_mainnet or any of the legacy mainnet network mainnet, aqua, or cyan 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.

      Plug n Play Project - Whitelist

  • Create a Verifier from the Custom Auth Section of the Web3Auth Developer Dashboard with following configuration:

    • Choose a name of your choice for the verifier identifier. eg. google-core-verifier
    • Select environment: Sapphire Devnet or Sapphire Mainnet as per your requirement.
    • Select Google from the Login Provider. Google - Login Providers list on Web3Auth Dashboard
    • Paste the Client ID from the Google App(above) to the Client ID field. Google Client ID on Web3Auth Dashboard
    • Click on the Create button to create your verifier. It may take up to 10 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 and the clientId of the project.

Setup your Next.js Project

If you're looking to create a nextjs application, follow the get started on Next.js.

Install the JWT library to decode the idToken

npm install jose --save

Note: We are using jose JWT library in this example, but feel free to use other JWT libraries.

Creating an API endpoint to validate the idToken

Update the pages/api/hello.ts file to include the following code:

// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import type { NextApiRequest, NextApiResponse } from "next";
import * as jose from "jose";

type Data = {
name: string;
};

export default async function handler(req: NextApiRequest, res: NextApiResponse<Data>) {
try {
const idToken = req.headers.authorization?.split(" ")[1] || "";
const app_pub_key = req.body.appPubKey;
const jwks = jose.createRemoteJWKSet(new URL("https://api.openlogin.com/jwks"));
const jwtDecoded = await jose.jwtVerify(idToken, jwks, {
algorithms: ["ES256"],
});

if ((jwtDecoded.payload as any).wallets[0].public_key == app_pub_key) {
// Verified
res.status(200).json({ name: "Validation Success" });
console.log("Validation Success");
} else {
// Verification failed
res.status(401).json({ name: "Validation Failed" });
console.log("Validation Failed");
}
} catch (error) {
res.status(500).json({ error: error.message });
}
}

Once your API endpoint is ready, you can validate the idToken from frontend with the following code:

const user = await web3auth.getUserInfo();

// parse the idToken from the user object
const base64Url = user?.idToken.split(".")[1];
const base64 = base64Url.replace("-", "+").replace("_", "/");
const parsedToken = JSON.parse(window.atob(base64));

// Validate idToken with server
const res = await fetch("/api/hello", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer " + user.idToken,
},
body: JSON.stringify({ appPubKey: parsedToken.wallets[0].public_key }),
});
if (res.status === 200) {
console.log("JWT Verification is Successful");
// allow login
} else {
console.log("JWT Verification Failed");
}

Using the Web3Auth SDK

To use the Web3Auth SDK, you need to add the dependency of the respective platform SDK of Web3Auth to your project. To know more about the available SDKs, please have a look at this documentation page.

For this guide, we will be talking through the Web3Auth Plug and Play No Modal SDK and using the OpenLogin Provider alongside it to enable Custom Authentication through Google Login.

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/no-modal @web3auth/openlogin-adapter @web3auth/ethereum-provider @web3auth/base web3

Understanding the Dependencies

Web3Auth Dependencies

@web3auth/no-modal

This is the main Core package that contains the Web3Auth SDK.

npm install --save @web3auth/no-modal
@web3auth/openlogin-adapter

For using Custom Authentication, we need to use the OpenLogin Adapter, where we can initialize the authentication details.

npm install --save @web3auth/openlogin-adapter
@web3auth/ethereum-provider

For using the EVM-compatible blockchains, we need to use the Ethereum Provider package, which will be used to connect to the blockchain.

npm install --save @web3auth/ethereum-provider
@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

Initialization

Once installed, your Web3Auth application needs to be initialized. Initialization is a 4 step process where we add all the config details for Web3Auth:

  1. Instantiation
  2. Configuration of Adapters
  3. Configuration of Plugins
  4. Initialization of the Web3Auth

Please make sure all of this is happening in your application constructor. This makes sure that Web3Auth is initialized when your application starts up.

For this guide, we're only focusing on the Instantiation, Configuration for the Openlogin Adapter (the default adapter that enables social logins) and Initialization of the Web3Auth SDK. To know more about the other things you can do with Web3Auth, check out our SDK Reference.

Instantiating Web3Auth

Importing the packages
import { WALLET_ADAPTERS, CHAIN_NAMESPACES, IProvider } from "@web3auth/base";
import { Web3AuthNoModal } from "@web3auth/no-modal";
import { OpenloginAdapter } from "@web3auth/openlogin-adapter";
import { EthereumPrivateKeyProvider } from "@web3auth/ethereum-provider";

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 SDK
import { Web3AuthNoModal } from "@web3auth/no-modal";
import { CHAIN_NAMESPACES } from "@web3auth/base";

const chainConfig = {
chainNamespace: CHAIN_NAMESPACES.EIP155,
chainId: "0x1",
rpcTarget: "https://rpc.ankr.com/eth",
displayName: "Ethereum Mainnet",
blockExplorer: "https://etherscan.io",
ticker: "ETH",
tickerName: "Ethereum",
};

const web3auth = new Web3AuthNoModal({
clientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ",
web3AuthNetwork: "sapphire_mainnet",
chainConfig,
});

Here, we're using the chainConfig property to set the chainId and chainNamespace. 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 Openlogin Adapter

const privateKeyProvider = new EthereumPrivateKeyProvider({
config: { chainConfig },
});

const openloginAdapter = new OpenloginAdapter({
adapterSettings: {
clientId: "YOUR-WEB3AUTH-CLIENT-ID", //Optional - Provide only if you haven't provided it in the Web3Auth Instantiation Code
uxMode: "popup",
loginConfig: {
google: {
name: "Name of your choice",
verifier: "YOUR-VERIFIER-NAME-ON-WEB3AUTH-DASHBOARD",
typeOfLogin: "google",
clientId: "YOUR-CLIENTID-FROM-GOOGLE",
},
},
},
privateKeyProvider,
});

web3auth.configureAdapter(openloginAdapter);

Here, you need to pass over your Web3Auth clientId in the adapterSettings object and your Custom Auth verifierName and AWS Cognito clientId in the loginConfig object. This makes sure that the Openlogin Adapter can connect to the correct verifier and AWS Cognito server.

Initializing the Web3Auth SDK

await web3auth.init();

Initializing on Mobile Platforms

  • For Mobile, depending on the platform, there will be different steps to initialize the SDK. Refer to the respective Mobile SDKs,

Authentication

Logging in

Once initialized, you can use the connectTo() function to authenticate the user when they click the login button.

import { WALLET_ADAPTERS, CHAIN_NAMESPACES } from "@web3auth/base";

await web3auth.connectTo(WALLET_ADAPTERS.OPENLOGIN, {
loginProvider: "google",
});

When connecting, your connectTo function takes the arguments for the adapter you want to connect to and the loginProvider for the login.

Get the User Profile

const user = await web3auth.getUserInfo();
console.log("User info", user);

Using the getUserInfo function, you can get the details of the logged in user. Please note that these details are not stored anywhere in Web3Auth network, but are fetched from the id_token you received from AWS Cognito and live in the frontend context.

Logout

await web3auth.logout();

Logging out your user is as simple as calling the logout function.

Interacting with 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

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

View User Balance

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

Sign Message

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

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

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

Example code

The code for the application we developed in this guide can be found in the Web3Auth Server Side Verification - Google Login Example. Check it out and try running it locally yourself!

Questions?

Ask us on Web3Auth's Community Support Portal