MetaMask – How to Verify a Signature on the Server Side

djangoecrecovermetamaskweb3.pyweb3js

I want my server to be able to authenticate a user based on whether or not they have the private key to their wallet. I am using web3.js in my front end, and web3.py in my backend.

The scenario will be something like this:

enter image description here

For now I only care about step 3 (without the nonce) and step 4.

This is the code I have in my front end:

        //Instantiate Web3
        const Web3 = require("web3");

        //Get Metamask web3 provider
        var web3 = new Web3(Web3.givenProvider);

        //Connect to Metamask (not sure how to do like web3.eth.connect)
        await window.ethereum.enable();

        //Get wallet address (public key)
        var accounts = await web3.eth.getAccounts();
        const walletAddress = accounts[0];

        //TO-DO: Message should be generated on server side with a nonce
        const message = "helloworld";

        //Sign message with Metamask (private key)
        const signedMessage = await web3.eth.personal.sign(
          message,
          walletAddress
        );

In my Django backend, I am creating an API like this:
http://localhost:8000/verify/claimedWallet/message/signedMessage

(This params convention looks off to me, but that was what was recommended in a Python Dev discord.)

How do I use web3.py to recover the address from the message and signed message?

Thanks!

Best Answer

Here is what worked for me:

You will need a Web3 provider, for example:

w3 = Web3(Web3.HTTPProvider('https://mainnet.infura.io/v3/api_key')

You can recover the address using the message and signature like so:

encoded_message = encode_defunct(bytes(message, encoding='utf8'))
recoveredAddress = w3.eth.account.recover_message(encoded_message , signature)
Related Topic