How to use Crypto Wallet for Authentication in ReactJS
Tags: javascript, react, webdev, beginners
Published: 2022-09-12 11:32:50

# Introduction

Authentication is an important aspect of an application to verify the identity of users. We use a combination of email/username with a password for authentication. Managing the password of various websites is a hectic job to do. We can also opt for OAuth for authentication such as Login with Google, FaceBook, Twitter, etc. You do not have to deal with password managers. This power comes with the cons of privacy. The website can request access to a variety of data from the OAuth application.

Web3 is rising and it has a better way of authenticating the user. We can use Crypto Wallets for authentication purposes. Using a crypto wallet for authentication will not require a managing password and your privacy will be protected. 

Crypto Wallets in the form of a hard wallet such as a USB stick or a web/mobile application form such as [Metamask](https://metamask.io/) allow people to exchange coins and tokens. Crypto Wallets have public/private keys. These wallets are protected by password or biometric authentication. To use the crypto wallet, the user needs to sign in to the wallet. As there are unique private keys for every user, we can use these crypto wallets for authenticating the user. 

Today, we are going to look into:
- Connect dApp to Wallet in our case MetaMask
- Getting a signature from the wallet
- Verifying signature for authentication

You can follow me on Twitter([@surajondev](https://twitter.com/surajondev)) as we will explore more authentication techniques in the future. Get the notification as soon as possible. 

So, let's get started.

# Environment Setup

We are going to use ReactJS for our front-end. React is for building the component-based frontend application.

Here is the command to install React:

```terminal
npx create-react-app crypto-auth
```

Delete all the unnecessary files and code. 

## Dependencies

As for dependencies, we only need one library i.e, ethers. Ethers will be helpful in interacting with our wallet. 

cd into the crypto-auth and enter the below command in the terminal:

```bat
npm i ethers
```

*Note: To run the above commands, you need to have [node.js](https://nodejs.org/en/download/) pre-installed.*

Download MetaMask wallet as a chrome extension from **[here](https://chrome.google.com/webstore/detail/metamask/nkbihfbeogaeaoehlefnkodbefgpgknn?hl=en)**

Now, we are all set for writing code. 

# App.js

In App.js file, at the top, we have to import the necessary libraries and CSS files. Here we have all the imports:

```jsx
import "./styles.css";
import { useState } from "react";
import { ethers } from "ethers";
```

In the functional component having the name `App` we are going to implement all the functionality of the authentication using the Crypto Wallet. 

As for the return statement, that contains the JSX of the component to display on the web page. We are going to have:
- `H1` displaying the title `Crypto Auth`
- Button to connect our application to Wallet(MetaMask)
- Message paragraph for displaying error/info for instance Login failed/ User Login successful
- If login happens, a paragraph to display the public key of the account

Here is the code:

```jsx
import "./styles.css";
import { useState } from "react";
import { ethers } from "ethers";

const cryptoButton = async () => {
  const [msg, setMsg] = useState();
  const [accnt, setAccnt] = useState();
    
  return (
    <div className="App">
      <h1>Crypto Authentication</h1>
      <button className="ConnectBtn" onClick={cryptoButton}>
        Connect Wallet
      </button>
      <p>{msg}</p>
      {msg === "User Login" && <div>Account: {accnt}</div>}
    </div>
  );
}
```

We have used the `cryptoButton` function to implement the code for connecting MetaMask. 

## cryptoButton

First, let's look into the code, and then I will explain each step. Here is the code:

```jsx
  const cryptoButton = async () => {
    const { ethereum } = window;
    if (ethereum.isMetaMask) {
      setMsg("MetaMask Installed");
      await ethereum.request({ method: "eth_requestAccounts" });
      const accounts = await ethereum.request({ method: "eth_accounts" });

      const provider = new ethers.providers.Web3Provider(ethereum);
      const signer = provider.getSigner();
      const message = randomString(16);
      const signature = await signer.signMessage(message);

      const signAddress = await ethers.utils.verifyMessage(message, signature);
      if (signAddress.toLowerCase() === accounts[0].toLowerCase()) {
        setMsg("User Login");
        setAccnt(accounts[0]);
      } else {
        setMsg("Login failed");
      }
    } else {
      setMsg("MetaMask is not installed");
    }
  };
```

At the top, we are extracting the ethereum object from the window. This function contains all the information regarding blockchain interaction. If MetaMask is installed, it injects its code into the ethereum object. Now, we have used the `ethereum.isMetaMask()` function to verify the valid installation of MetaMask. We will progress only if the MetaMask is installed as the browser extension. Otherwise, it will set a message with `MetaMask is not installed`. 

With the next two lines, we are accessing the account details from the wallet. This will make a request to the MetaMask. After that, we are storing the public key from the wallet in the `accounts` variable. The public key will be in the array format. 

```javascript
await ethereum.request({ method: "eth_requestAccounts" });
const accounts = await ethereum.request({ method: "eth_accounts" });
```

At this point, we have successfully connected our application with MetaMask. We need to get a signature from the wallet user. As anyone with API can inject the pubic key but the signature require a private key which makes it a valid authentication.

## Signature

Here is the code for getting the signature:
```jsx
      const provider = new ethers.providers.Web3Provider(ethereum);
      const signer = provider.getSigner();
      const message = randomString(16);
      const signature = await signer.signMessage(message);
```

In the first line, we are getting the provider. A Provider in ethers is a read-only abstraction to access the blockchain data. From the provider, we are accessing the `getSigner()` function and storing it into the `signer` variable. We need to pass a message to which the wallet will sign. You can pass a message like "Welcome to Crypto Auth". It will be shown to the user will signing the message.

![Message sign](https://cdn.hashnode.com/res/hashnode/image/upload/v1662883668438/qiOm6l4eB.png)

This message is used to create the signature. Complicating the signature will make it harder to decode. So passing a nonce is ideal. A nonce is an arbitrary number that is unique for each user.  This nonce can be alphanumeric or big numbers. You can store this nonce for each user in the database. As we are not connecting our application to the database, we need not insure uniqueness, so I have created `randomString(16)` function to provide us with random alphanumeric values. 16 as an argument is for 16 characters of the string.

Here is the code for the `randomString()` function:
```javascript
const randomString = function (length) {
  var text = "";
  var possible =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
  for (var i = 0; i < length; i++) {
    text += possible.charAt(Math.floor(Math.random() * possible.length));
  }
  return text;
};
```
After that, we are getting the signature from the user through the wallet. 

## Signature Verification

After getting the signature, we need to verify that the public key from the wallet that's signing the signature is the same as the public key that we requested earlier. 

In ethers library, there is a function, `ethers.utils.verifyMessage()`, for verification of signature. This function takes nonce (In our case, we have stored the nonce in the variable having a name message) and signature as the argument. The function returns the public key that has signed the message.

```javascript
const signAddress = await ethers.utils.verifyMessage(message, signature);
```

Now, we have two public keys. The first one is from the earlier request to the wallet and the second one is from the signed message. We just need to make sure that both public keys are the same.

```jsx
if (signAddress.toLowerCase() === accounts[0].toLowerCase()) {
        setMsg("User Login");
        setAccnt(accounts[0]);
} else {
        setMsg("Login failed");
}
```
We have converted both the public key into lowercase for verification.  The message will be displayed according to the verification. 

Here is the code of the App.js altogether at once:

```jsx
import "./styles.css";
import { useState } from "react";
import { ethers } from "ethers";

const randomString = function (length) {
  var text = "";
  var possible =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
  for (var i = 0; i < length; i++) {
    text += possible.charAt(Math.floor(Math.random() * possible.length));
  }
  return text;
};

export default function App() {
  const [msg, setMsg] = useState();
  const [accnt, setAccnt] = useState();

  const cryptoButton = async () => {
    const { ethereum } = window;
    if (ethereum.isMetaMask) {
      setMsg("MetaMask Installed");
      await ethereum.request({ method: "eth_requestAccounts" });
      const accounts = await ethereum.request({ method: "eth_accounts" });

      const provider = new ethers.providers.Web3Provider(ethereum);
      const signer = provider.getSigner();
      const message = randomString(16);
      const signature = await signer.signMessage(message);

      const signAddress = await ethers.utils.verifyMessage(message, signature);
      if (signAddress.toLowerCase() === accounts[0].toLowerCase()) {
        setMsg("User Login");
        setAccnt(accounts[0]);
      } else {
        setMsg("Login failed");
      }
    } else {
      setMsg("MetaMask is not installed");
    }
  };
  return (
    <div className="App">
      <h1>Crypto Authentication</h1>
      <button className="ConnectBtn" onClick={cryptoButton}>
        Connect Wallet
      </button>
      <p>{msg}</p>
      {msg === "User Login" && <div>Account: {accnt}</div>}
    </div>
  );
}

```

# Demo

If everything goes well you can see the below screen.

![homepage](https://cdn.hashnode.com/res/hashnode/image/upload/v1662886018889/ypdqg6m9Q.png)

[homepage](https://cdn.hashnode.com/res/hashnode/image/upload/v1662885755285/_MuP_vbHO.png)

Now, if you click on the `Connect Wallet` button. Your MetaMask will pop up asking for a signature with the message.

![sign message](https://cdn.hashnode.com/res/hashnode/image/upload/v1662885851939/FBBrql4Wb.png)

After you click on `Sign`, you will see the public key from the wallet on the screen. 

![verified public key](https://cdn.hashnode.com/res/hashnode/image/upload/v1662885964210/W_hqgvvuN.png)

# Extending the project

You can extend the project by adding a database in the backend. You can use [MongoDB Atlas](https://www.mongodb.com/atlas/database) for database.

# Connect With Me

- [Twitter](https://twitter.com/surajondev)
- [LinkedIn](https://www.linkedin.com/in/surajondev/)

# Conclusion

We have successfully created a button that will surely connect your application to the wallet (MetaMask). In this way, you need to worry about the password and all. 

I hope, the article has benefitted you with more knowledge. Thanks for reading the blog post.