1

What is the best practice for users to securely send a POST to an API with their Ethereum address? My inclination is to have the user sign a message with their private key, send the resulting signature to the backend, and recover the public key on the backend using the same message and signature.

Most importantly, is this flow (1) correct and (2) secure? I assume signatures cannot be faked without knowing some private key. The API would be public, and the signature used in lieu of JWTs as the only means of authentication.

Secondly, if the above is correct and secure, what are the recommended methods to have users sign transactions? I see 3 methods of signing transactions in Web3.js with unclear differences between them:

  1. web3.eth.sign(dataToSign, address [, callback])

  2. web3.eth.personal.sign(dataToSign, address, password [, callback])

  3. web3.eth.accounts.sign(data, privateKey); (Client would obviously not have privateKey)

And 1 method to recover the account that signed the data:

  1. web3.eth.personal.ecRecover(dataThatWasSigned, signature [, callback])

Which methods are recommended and why?

Lastly, is the message itself important? I assume it can be anything as long as the backend and client have the same one, but users should also feel confident that signing a given message cannot be used nefariously.

1
+50

The first three methods produce the same signature by different means. They are different paths to the private key needed to sign.

  1. Without knowing the private key or the password for the account, the client uses the unlocked account/address to sign the message.
  2. Without having an account necessarily unlocked, the client uses the known password to obtain the private key and sign the message. In effect, that unlocks the account just long enough to sign the message.
  3. Without necessarily knowing the account/address (rare?), the client uses knowledge of the private key that it already has (somehow) to sign the message.

I'm not sure one method is recommended while the others are not since that would imply that the others are unnecessary or possibly dangerous. Starting with the situation at the moment where you need to generate a signature one will seem more natural than the others. Having said that, appropriate precautions are necessary when working directly with private keys (third option) to prevent accidental leakage.

is the message itself important?

Yes, or else the same signature could be used to authenticate more than one message. That is potentially disastrous if the signature pattern becomes compromised and the server continues to accept the same signature.

The message itself is a good candidate for the message to sign.

Consider:

{
  "sig": "0x456...",
  "payload": { 
    "from:", "0x789...",
    "arg1": "foo",
    "arg2": "bar"
  }
}

Let the sender hash the payload and sign the hash. Let the receiver hash the payload and then ecrecover the signer. The server can confirm that "foo", "bar" came "from" the signer because ecrecover and from should match. If this is not the case then reject the message because someone else signed it or the signature is invalid.

Hope it helps.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.