Ether – How to Send Signed Data to Backend and Verify It

etherjavascriptsignaturetimestamp

On a web page I have some 3 fields, name, age and height, which a user authenticated via MetaMask sends to backend along with his wallet address. In JSON.

In order to ensure that data that's sent hasn't been tampered and his wallet address indeed belongs to him, I'll have to ask a user to sign data, right? I'm aware of how to do it:

 let mySigData = await this.mySigner.signMessage(ethers.utils.arrayify("some data"));

I'll also include a timestamp in data to prevent re-usage of a signature.

However, what is it what I actually will have to send from a client to then send to backend? What will all the data (data + payload) look like?

And how will I then deconstract it on a server properly?

Option #1

{
  name: "name1",
  age: 367,
  height: 188, 
  sig: "fdsafdsafdsafds$$2fds####",
  timestamp: 1236366
}

Option #2

{
  sig: "#6$$,,##$$-safd8543gfds", //name, age and height have somehow been embeded here 
  timestamp: 1236366
}

I'm aware how to verify a signature itself in ether.js but I mean the whole data itself.

On a server I'll then call …. what?

  const verify = ethers.utils.verifyMessage("???", params["sig"])

Best Answer

As an example, your data structure could be:

let user = {
    data: {
        name: 'name1',
        age: 367,
        height: 188, 
        timestamp: 1236366,
    },
    address: '0x<UserAddress>',
    sig: '...'
}

Signing

To sign the data you must serialize it and the most simple serialization would be to use JSON.stringify

let message = utils.arrayify(JSON.stringify(user.data);
user.address = await this.mySigner.getAddress();
user.sig = await this.mySigner.signMessage(message);

Recover Address

On the backend side, after receiving the user object, you should serialize the data in the same manner and recover the address with the signature:

let message = utils.arrayify(JSON.stringify(params.data);
let address = utils.verifyMessage(message, params.sig);

Depending on your further logic you can check:

  1. if params.address is equal to the recovered address
  2. if the address is allowed to submit data
  3. ...

The most important key point here, regardless of the data structure you choose, is that it depends on your business logic. The serialization of the data takes place on the front end for signing. Subsequently, the raw data along with the signature is sent to the backend. The backend serializes the data in the same way and verifies if it can be retrieved for the expected address using the provided signature.

Related Topic