October 30, 2022

Sign In With Any Wallet to Your Web3 App

Table of Contents

Web3 authentication is essential to building Web3-compatible projects as it provides a more compelling user experience and lowers onboarding friction. Moreover, did you know you can seamlessly add sign in functionality with any wallet using Moralis? If this sounds interesting, read on and learn all you need to know about Web3 authentication! 

Full Sign In With Any Wallet Documentation – https://github.com/MoralisWeb3/youtube-tutorials/tree/main/MultipleWalletAuthentication 

This article will demonstrate how you can add sign in functionality with any wallet to your Web3 projects. If you do not want to read the complete guide, you can find the entire code in the GitHub repository above. However, if you follow along, we will explain Moralis’ Auth API and the code in further detail so you can sign in with any wallet to your Web3 app. We will also explore additional authentication methods or alternatives that Moralis supports, all of which are an implementation of the EIP-4361 standard. As a result, once you are done reading, you will hopefully know how to implement several different Web3 wallet authentication mechanisms in all future projects. 

Furthermore, Moralis’ Auth API is only one of the many valuable tools of the platform. Moralis also, for example, supplies a sophisticated NFT API, making it possible to easily and seamlessly develop NFT-related projects.  

So, make sure to sign up with Moralis, as the platform supplies a more seamless developer experience. Moralis can be helpful in all Web3 development endeavors, and creating an account is entirely free! 

Sign In With Any Wallet

Are you looking to create a new Web3 dapp, merge an existing Web2 database with Web3 authentication, or use auth aggregators such as Auth0 for your business’ authentication flow? If you are – or might find yourself in any of these situations – then the Moralis Web3 Auth API is just what you need! 

From a traditional perspective, implementing Web3 authentication mechanisms into dapps and other decentralized projects has always been a cumbersome task. It has generally required developers to redirect users to third-party authentication interfaces, master varying wallet standards, update and maintain auth solutions, etc. However, this is no longer the case with Moralis’ Web3 Auth API. 

Moralis provides a unified API for all various authentication methods with a sophisticated SDK allowing for easy integration. Moreover, the API is compatible with other authentication aggregators and constantly adds new authentication mechanisms. Thus, when working with Moralis’ API, you ensure that your authentication flows are future-proof in a fast-moving industry. 

Moralis’ Auth API supercharges your project’s auth capabilities allowing your users to sign in with any wallet. The development tool combines the power of Web3 technology with the accessibility of Web2 development. You can, therefore, provide users with the safest and most straightforward way to sign up for all your projects. 

Moreover, the API is cross-chain compatible, suggesting you can integrate Web3 authentication with only one line of code for multiple different chains. As a result, when working with Moralis, you do not need to waste unnecessary time on complex integration. 

Additionally, using the API eliminates onboarding friction and future-proofs your authentication flows in a rapidly evolving industry. So, if you want to create Web3-compatible projects, you can try out the API for free by signing up with Moralis! 

Using Moralis to Add Sign In Functionality With Any Wallet

With a more profound understanding of Moralis’ Auth API, we will now illustrate the power of this tool by showing you how to sign in with any wallet. Moving forward, we will create a simple application where users can sign in with MetaMask, WalletConnect, or Coinbase Wallet. We will use these as examples as we, unfortunately, do not have time to cover all options Moralis supports. Nonetheless, no matter which authentication method you are looking to add, the entire process remains the same, with a few tweaks here and there. 

To demonstrate what we will create during this tutorial, we will supply two screenshots: one for the login page and one for the user page:

Login Page: 

User Page:

As you can see from the images above, the login page features three authentication buttons for each alternative. To create this straightforward application, you simply need to visit the GitHub repository to which we linked initially and download the code to your local repository. 

With all the code at your disposal, you must install all the necessary dependencies and run a local dev server. Running a local dev server will ensure the project is compiled on “local host 3000“, meaning you can test the application easily. Nonetheless, here are the two commands you need to run: 

npm i 
npm run dev

This is basically it for creating this simple application; however, we will explain in the following section how the code works. In turn, it will make it easier for you to add sign in functionality with any wallet to your future projects. 

Moreover, if you prefer watching videos to educate yourself, check out the clip below from Moralis’ YouTube channel for a complete walkthrough of the application and how to set it up: 

Code Walkthrough: Add Sign In Functionality With Any Wallet

We will divide the code walkthrough into two sections, one for the backend and the other for the frontend. Doing so will hopefully provide insight into how you can add sign functionality with any wallet using Moralis. Unfortunately, we will not have time to cover all aspects of the code. Thus, if you have any further questions, make sure to check out the complete code at the GitHub repo. But, without further ado, let’s jump straight into the code, starting with the “api/auth” folder! 

Auth API to Add Sign In Functionality With Any Wallet

The “api/auth” folder contains two separate files. The first one we will look closer at is an endpoint for requesting a message. Meanwhile, the second one is for verifying the message. Nonetheless, let’s dissect each file and start by looking closer at the endpoint for requesting a message. So, this is what the code for the file looks like:

import Moralis from 'moralis';

const config = {
    domain: process.env.APP_DOMAIN,
    statement: 'Web Login.',
    uri: process.env.NEXTAUTH_URL,
    timeout: 60,
};

export default async function handler(req, res) {
    const { address, chain, network } = req.body;

    await Moralis.start({ apiKey: process.env.MORALIS_API_KEY });

    try {
        const message = await Moralis.Auth.requestMessage({
            address,
            chain,
            network,
            ...config,
        });

        res.status(200).json(message);
    } catch (error) {
        res.status(400).json({ error });
        console.error(error);
    }
}

The code above will trigger the “Moralis.Auth.requestMessage()” function using the address and chain ID of the users. Further, this will create a new message sent to the client side for the users to sign. Once signed, another post request is sent, which takes us to the code for the second file: 

import CredentialsProvider from 'next-auth/providers/credentials';
import NextAuth from 'next-auth';
import Moralis from 'moralis';

export default NextAuth({
    providers: [
        CredentialsProvider({
            name: 'MoralisAuth',
            credentials: {
                message: {
                    label: 'Message',
                    type: 'text',
                    placeholder: '0x0',
                },
                signature: {
                    label: 'Signature',
                    type: 'text',
                    placeholder: '0x0',
                },
            },
              async authorize(credentials) {
                try {
                  // "message" and "signature" are needed for authorisation
                  // we described them in "credentials" above
                  const { message, signature } = credentials;

                  await Moralis.start({ apiKey: process.env.MORALIS_API_KEY });

                  const { address, profileId } = (
                    await Moralis.Auth.verify({ message, signature, network: 'evm' })
                  ).raw;

                  const user = { address, profileId, signature };
                  // returning the user object and creating  a session
                  return user;
                } catch (e) {
                  console.error(e);
                  return null;
                }
              },
        }),
    ],
    // adding user info to the user session object
    callbacks: {
        async jwt({ token, user }) {
            user && (token.user = user);
            return token;
        },
        async session({ session, token }) {
            session.user = token.user;
            return session;
        },
    },
});

As this code illustrates, another request is sent to the “Moralis.Auth.verify()” function using the response from the first request, which is the message, and the signature used to sign the message on the client side. 

Following this, a user is generated using “next.auth” with the user’s address, profile ID, and signature. This user will then be stored in a web session in a JWT (JSON web token). So, that’s it for the backend/auth API part of the code; let’s move on and take a closer look at the frontend. 

Frontend to Add Sign In Functionality With Any Wallet

Next up, we are going to take a closer look at the frontend of the app. We have several setup files here, such as “_app.js”, “index.js”, etc. However, we will focus on the “signin.js” file as this is where we can find most of the essential logic for the various authentication alternatives.

At the top of this file, you will notice a few imports. We are particularly interested in the connectors where we bring in the various authentication options using wagmi. Essentially, this is what you will use for all the client-side Web3 connections. Moreover, this is what it looks like in the code: 

import { signIn } from "next-auth/react";
import { useAccount, useConnect, useSignMessage, useDisconnect } from "wagmi";
import { useRouter } from "next/router";
import { MetaMaskConnector } from "wagmi/connectors/metaMask";
import { CoinbaseWalletConnector } from "wagmi/connectors/coinbaseWallet";
import { WalletConnectConnector } from "wagmi/connectors/walletConnect";
import axios from "axios";

The “handleAuth(wal)” Function

Following the imports, we will focus on the “handleAuth(wal)” function, where we create a connection using the various wallet connectors. The “wal” argument specifies which alternative is to be used. However, before establishing the connections, we create a “userData” const, used to store information regarding users. Nevertheless, this is what the first part of the function looks like: 

 const handleAuth = async (wal) => {
    if (isConnected) {
      await disconnectAsync();
    }

    console.log("Connect To Site Via Wallet");

    const userData = { network: "evm" };

Following this, we have three “if” statements for the various alternatives, and it looks like the following: 

 if (wal === "meta") {
      const { account, chain } = await connectAsync({
        connector: new MetaMaskConnector({}),
      });
      userData.address = account;
      userData.chain = chain.id;
    }

    if (wal === "coin") {
      const { account, chain } = await connectAsync({
        connector: new CoinbaseWalletConnector({}),
      });
      userData.address = account;
      userData.chain = chain.id;
    }

    if (wal === "wal") {
      const { account, chain } = await connectAsync({
        connector: new WalletConnectConnector({ options: { qrcode: true } }),
      });
      userData.address = account;
      userData.chain = chain.id;
    }

Let’s take the first one as an example. In the first statement, “if (wal === “meta””, the code will use the “MetaMaskConnector” to establish a connection. Further, once the connections are set, we have the wallet address and chain ID, which are added to the “userData” const.

We then utilize this information to send a post request to the Moralis Auth API:

console.log("Sending Connected Account and Chain ID to Moralis Auth API");

    const { data } = await axios.post("/api/auth/request-message", userData, {
      headers: {
        "content-type": "application/json",
      },
    });

With the message at hand, we use wagmi again to sign the message and then send the final post request to Moralis authentication to verify and create that user JWT that we lastly push to the user’s page: 

console.log("Received Signature Request From Moralis Auth API");

    const message = data.message;

    const signature = await signMessageAsync({ message });

    console.log("Succesful Sign In, Redirecting to User Page");

    const { url } = await signIn("credentials", {
      message,
      signature,
      redirect: false,
      callbackUrl: "/user",
    });

    push(url);

To top everything off, we create a button for each alternative where we run the “handleAuth(wal)” function with different parameters corresponding to the various “if” statements from before: 

<div>
      <h3>Web3 Authentication</h3>
      <button onClick={() => handleAuth("meta")}>
        Authenticate via Metamask
      </button>
      <br />
      <button onClick={() => handleAuth("coin")}>
        Authenticate via Coinbase
      </button>
      <br/>
      <button onClick={() => handleAuth("wal")}>
        Authenticate via Wallet Connect
      </button>
    </div>

That’s it for the essential parts, and this is what the final product of the “signin.js” file should look like:  

import { signIn } from "next-auth/react";
import { useAccount, useConnect, useSignMessage, useDisconnect } from "wagmi";
import { useRouter } from "next/router";
import { MetaMaskConnector } from "wagmi/connectors/metaMask";
import { CoinbaseWalletConnector } from "wagmi/connectors/coinbaseWallet";
import { WalletConnectConnector } from "wagmi/connectors/walletConnect";
import axios from "axios";

function SignIn() {
  const { connectAsync } = useConnect();
  const { disconnectAsync } = useDisconnect();
  const { isConnected } = useAccount();
  const { signMessageAsync } = useSignMessage();
  const { push } = useRouter();

  const handleAuth = async (wal) => {
    if (isConnected) {
      await disconnectAsync();
    }

    console.log("Connect To Site Via Wallet");

    const userData = { network: "evm" };

    if (wal === "meta") {
      const { account, chain } = await connectAsync({
        connector: new MetaMaskConnector({}),
      });
      userData.address = account;
      userData.chain = chain.id;
    }

    if (wal === "coin") {
      const { account, chain } = await connectAsync({
        connector: new CoinbaseWalletConnector({}),
      });
      userData.address = account;
      userData.chain = chain.id;
    }

    if (wal === "wal") {
      const { account, chain } = await connectAsync({
        connector: new WalletConnectConnector({ options: { qrcode: true } }),
      });
      userData.address = account;
      userData.chain = chain.id;
    }

    console.log("Sending Connected Account and Chain ID to Moralis Auth API");

    const { data } = await axios.post("/api/auth/request-message", userData, {
      headers: {
        "content-type": "application/json",
      },
    });

    console.log("Received Signature Request From Moralis Auth API");

    const message = data.message;

    const signature = await signMessageAsync({ message });

    console.log("Succesful Sign In, Redirecting to User Page");

    const { url } = await signIn("credentials", {
      message,
      signature,
      redirect: false,
      callbackUrl: "/user",
    });

    push(url);
  };

  return (
    <div>
      <h3>Web3 Authentication</h3>
      <button onClick={() => handleAuth("meta")}>
        Authenticate via Metamask
      </button>
      <br />
      <button onClick={() => handleAuth("coin")}>
        Authenticate via Coinbase
      </button>
      <br/>
      <button onClick={() => handleAuth("wal")}>
        Authenticate via Wallet Connect
      </button>
    </div>
  );
}

export default SignIn;

If you have questions regarding the code, look closer at the complete code from the GitHub repository stated at the outset of this article. You can also take a closer look at the video above explaining the process in further detail! 

So, that’s it for this brief tutorial showing you how to sign in with any wallet. The following section will discover additional methods for authenticating users with Moralis! 

Moralis Authentication Alternatives

In the previous section, we illustrated how to authenticate users with MetaMask, WalletConnect, and Coinbase Wallet. If you have further interest in these authentication alternatives, we have other guides that you might find interesting. For example, check out our guides on how to add Coinbase Wallet login functionality or integrate backend Web3 authentication functionality. 

However, the options mentioned above are only three examples that Moralis offer. In the following sections, we will look closely at some additional alternatives! 

Add Sign In with RainbowKit

In addition to the popular alternatives mentioned previously, Moralis also has support for RainbowKit. As such, you can use Moralis to easily implement support for RainbowKit in your current or future blockchain projects. So, if you find this interesting, read more about it in our “How to Add a Sign In with RainbowKit” tutorial! 

Add Sign In with Magic.Link

Another exciting Moralis authentication alternative is Magic.Link. Implementing support for Magic.Link will allow users to sign in to your projects without needing an account or a password. Instead, they must enter their email address, and they will receive a link. Once they press the link, they will be authenticated. Check out the following article for more information on implementing support for Magic.Link: “Add Sign-In with Magic.Link to Your NextJS Project in 5 Steps“.

Add MetaMask Authentication with Django

Moralis allows for easy integration of MetaMask authentication into all projects. Moreover, the platform features several alternatives in which you can implement support for MetaMask. An example here is Django, a popular framework for Python. If you want to learn more about this, check out our guide on how to add MetaMask authentication with Django.  

These are only some examples of authentication options and methods for implementing support. Moralis offers additional alternatives allowing you to add sign in functionality with any wallet. As a result, when working with the platform, you do not limit yourself to one option!

Sign In With Any Wallet – Summary

This tutorial taught you how to add sign in functionality with any wallet. To demonstrate the power of Moralis’ Auth API, we showed how you could create a simple application allowing users to authenticate with MetaMask, WalletConnect, and Coinbase Wallet. Thanks to the Moralis platform, we were able to easily implement these three methods with a few lines of code. 

In addition to creating the application, we also explored some further authentication alternatives. Hence, we learned that Moralis, for example, offers support to implement authentication mechanisms for Magic.Link and RainbowKit.

If you found Web3 authentication accessible through Moralis, you should also know that this is only one area in which Moralis shines. For example, you can easily implement Web3 syncs and create Web3 webhooks

Moreover, if you want to learn more about blockchain development in general, explore further content here at Moralis’ Web3 blog. We recommend reading our articles regarding blockchain syncs or Moralis’ NodeJS SDK for Web3. Additionally, you can sign up with Moralis for free and start creating sophisticated Web3 projects in minutes! So, make sure to create your account right now and access all the platform’s tools to make your Web3 development endeavors more accessible!

Moralis Money
Stay ahead of the markets with real-time, on-chain data insights. Inform your trades with true market alpha!
Moralis Money
Related Articles
January 30, 2024

Exploring the Cosmos Ecosystem – List of the Best Cosmos Projects

January 30, 2023

OpenZeppelin in Remix – Importing OpenZeppelin Contracts in Remix

September 17, 2022

How to Set Up a Self-Hosted Web3 Server

October 31, 2023

Complete Blockchain API Tutorial with API Examples

December 12, 2022

How to Get the Token Balance of an Address

January 12, 2024

Full List of DEXs – Best Decentralized Crypto Exchanges

February 27, 2024

How to Get the Net Worth of Any ERC20 Wallet via API