User Authentication with Web3
Tags: web3, crypto, javascript, tutorial
Published: 2022-08-18 16:28:00

Hi, I'm assume you're familiar with Web3, and have understanding about cryptography, DeFi or Web3 Project.

I will introduce you to a new way of User Authentication using Web3 technology (Actually using power of Cryptography).

If you ever land yourself to DeFi or Web3 Project, you must be aware that the platform never force you to Login into platform. It's simply because in Web3, we don't store your personal information. We recognize you by your signature (We're not talking about your handwrite signature, it's about [Digital Signature](https://en.wikipedia.org/wiki/Digital_signature)).

You also must be aware that you will require to install a [Wallet](https://www.investopedia.com/terms/b/bitcoin-wallet.asp) to join into Web3/Blockchain World. This wallet will be used to manage your private key, and used to sign your transaction that will be send to blockchain. (By any chance, **NEVER SHARED YOUR PRIVATE KEY**)

Currently, I have a "hybrid" project. I called this project "hybrid" because it utilize power of web3 but most the feature are web2.


<br>
![What are you talking?!](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4yqwn3lwb4krarywpmrg.jpeg)
<br>


It must be a bit confusing, I will give you a litte context. So, the Play to Earn games is getting hype in Web3 World. There is a lot of games like [Axie Infinite](https://axieinfinity.com/), [Splinterlands](https://splinterlands.com/), [Sandbox](https://www.sandbox.game/en/) and many more. And my current project is a Play to Earn games, users will need to buy a NFT, and then used their NFT to play and gained reward. 

After a research that have been done by UX team, they found that most of crypto games are a bit annoying to players because it need to do a lot of signing using Wallet, and this submitting process to blockchain is not cheap (At that time, Gas Price on Ethereum was Crazy).

Engineer team also consider that most of game data (data that generated when player play the games) is not necessary to be written on blockchain. So we decided to using NoSQL Database to store game data. And then UX team asking about how the user onboard to the games? Do they need to login using Email/Username & Password?. Well, login using email and password just not really "Web3 things".

We want to identified the player without taking their personal information. So we decide to utilize the essential power of Blockchain. **The Cryptography Signing**.

<br>
![Yohohohoo](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7i7d70vz8for3xqzajmq.jpeg)
<br>

So, I will show you how to make user authentication on **EVM Blockchain Based**, using **Ethers.js** & **Metamask**. You can pick any framework for your Backend.

![Web3 Login Mechanism](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2sai10r90s3f6r6mndq1.png)
 
 
#### User request Nonce to Backend
User will send request to Backend to retrieve information about User's [Nonce](https://en.wikipedia.org/wiki/Cryptographic_nonce). 

#### Backend send Nonce to User.
User will retrieve the Nonce. User will construct a message that contain information about the Nonce. Let say the nonce is 100, the message will be is `Hi I wanna play the Games | 100`

#### User Sign Message & Wallet Generate Signature
User need to sign a message, we will utilize ethers.js library.
```
// This nonce come from Backend
const nonce = 100;

// Get User's Public Key
const [account]: string[] = await window.ethereum.request({
    method: 'eth_requestAccounts',
});
const publicKey = await ethers.utils.getAddress(account);

// Sign Message
const provider = new ethers.providers.Web3Provider(window.ethereum);
const signer = provider.getSigner();
const message = `Hi I wanna play the Games | ${nonce}`;
const messageUtf8Bytes = ethers.utils.toUtf8Bytes(message);
const testBytes = ethers.utils.arrayify(messageUtf8Bytes);
const signature = await signer.signMessage(testBytes);
const accountSignature = {
    publicKey: publicKey,
    message: message,
    signature: signature,
};
```

#### User submit Signature, Message & Public Key
After sign the message, user will get the signature. User need to submit Signature, Message & Public Key to Backend. 

#### Verify & Validate Signature
User received Signature, Message & Public Key. Backend will check the Nonce on the message, this Nonce must be correct with the Nonce that written on Backend Database. To Validate the Signature, Backend will need to utilize ethers.js library.
```
const checkValidSignature = (message, signature, pubKey) => {
  const messageUtf8Bytes = ethers.utils.toUtf8Bytes(message);
  const arrayifyMessage = ethers.utils.arrayify(messageUtf8Bytes);
  const recoveredAddress = ethers.utils.verifyMessage(
    arrayifyMessage,
    signature
  );
  const publicKeyLowerCase = pubKey.toLowerCase();
  const recoveredAddressLowerCase = recoveredAddress.toLowerCase();
  if (publicKeyLowerCase === recoveredAddressLowerCase) {
    return true;
  }
  return false;
};
```

#### Send Auth Token
If the signature is valid and user send correct nonce, Backend will give Authentication Token to User. This token will be used by user to authenticate themself when play the game.

<br>
So, we are not store any Personal Information about users. We don't have a **Users table** on Backend to store user's username & password.


<br>
This is an adequate method that you can apply when build Hybrid apps. You still able to identified your users without collecting their personal information.

<br>
**Notes**
In step above, we signing message using standard [EIP-191](https://eips.ethereum.org/EIPS/eip-191). If you consider about to have more complex message to sign, you can use [EIP-712](https://eips.ethereum.org/EIPS/eip-712)