Is there any way to do that? To recover address in nodejs server-side from signature and message after it was signed with web3.personal.sign client-side? I tried this: https://ethereum.stackexchange.com/a/12580/42452 with ethereumjs-util; I tried recoverTypedSignature() from eth-sig-util but in both cases recovered addresses didn't match signing addresses.

Here is the client-side code:

function authorize() {
  web3.eth.getAccounts(function (err, account) {
    let nonce = "123ABC";
    web3.personal.sign(nonce, account[0], function (err, signature) {
      //send to nodejs server
      $.post("http://localhost:8087", {signature: signature, nonce: nonce, address: account[0]}, function (data) {

and server-side:

app.post('/', cors(corsOptions), function(req, res){
const msg = web3.sha3(nonce);
const sig = signature;
const {v, r, s} = util.fromRpcSig(sig);

const pubKey  = util.ecrecover(util.toBuffer(msg), v, r, s);
const addrBuf = util.pubToAddress(pubKey);
const addr    = util.bufferToHex(addrBuf);

  • It's hard to debug your code when you haven't shared it.
    – user19510
    Commented Apr 17, 2019 at 22:05

5 Answers 5


So, after many hours, I found a solution, that works. To make it works I used method from ethereumjs-util - ecrecover. I had to add some prefixed message to signed nonce. Code looks like this:

function checkSignature(nonce, signature, res) {

  nonce = "\x19Ethereum Signed Message:\n" + nonce.length + nonce;
  nonce = util.keccak(nonce);
  const sig = signature;
  const {v, r, s} = util.fromRpcSig(sig);
  const pubKey  = util.ecrecover(util.toBuffer(nonce), v, r, s);
  const addrBuf = util.pubToAddress(pubKey);
  const addr    = util.bufferToHex(addrBuf);

  • I get this: Error: This method only supports Buffer but input was: Ethereum Signed Message. My Signature was done in frontend: web3.eth.personal.sign("Hello world", account[0], "test password!") | edit: maybe I need to do this in my frontend as well: nonce = "\x19Ethereum Signed Message:\n" + nonce.length + nonce; nonce = util.keccak(nonce); before I let the user sign the nonce.
    – Suisse
    Commented Apr 5, 2021 at 17:08
  • so I did this: nonce = util.keccak(Buffer.from(nonce)); - no error, but I get a diffrent addr than the user who signed! Do I need to do something special in the frontend instead of: web3.eth.personal.sign(nonce, from[0], "test password!")
    – Suisse
    Commented Apr 5, 2021 at 17:36

Did you try web3's web3.eth.personal.ecRecover?

For example, if you sign via

web3.eth.personal.sign("Hello world", "0x11f4d0A3c12e86B4b5F39B213F7E19D048276DAe", "test password!")

> "0x30755ed65396facf86c53e6217c52b4daebe72aa4941d89635409de4c9c7f9466d4e9aaec7977f05e923889b33c0d0dd27d7226b6e6f56ce737465c5cfd04be400"

You "recover" via...

web3.eth.personal.ecRecover("Hello world", "0x30755ed65396facf86c53e6217c52b4daebe72aa4941d89635409de4c9c7f9466d4e9aaec7977f05e923889b33c0d0dd27d7226b6e6f56ce737465c5cfd04be400").then(console.log);

> "0x11f4d0A3c12e86B4b5F39B213F7E19D048276DAe"

  • Sure I tried "web3.eth.personal.ecRecover", but it gives me error: "Cannot read property 'ecRecover' of undefined". Then I tried web3.personal.ecRecover, but this method produces error: "The method personal_ecRecover does not exist/is not available". So to me, it looks like the personal.ecRecover method works only in the browser, client-side, but not inside nodejs server-side. But after many hours I found a solution. Commented Apr 18, 2019 at 12:18
  • 1
    Interesting. The personal interactions are typically limited to a client-side solution (the personal is also used for creating accounts, signing transactions, etc. and is dangerous to have that happening on an open, server node.) I wonder why this is personal though. Regardless, can you please post an answer to your question as a new answer to help people who may have similar issues in the future?
    – tayvano
    Commented Apr 18, 2019 at 18:29
  • Do I understand this right: with sig() we get a signature based on a pre defined nonce ("Hello world") and afterwards, without having a private key, we can find out that the signature is really from the account we assume it should be? And what is the third argument of sing() the password?
    – Suisse
    Commented Apr 5, 2021 at 15:34

Aug 2021

I achieve this by installing the npm package called eth-sig-util.

Here is my code:

const ethSigUtil = require("eth-sig-util");

function checkSignature(nonce, signature) {
    const msgParams = {
        data: nonce,
        sig: signature
    return ethSigUtil.recoverPersonalSignature(msgParams);

Try this:

const recovered = web3.eth.accounts.recover("Some data"/*the unhashed message*/, "0xb3bd48482d2c13a1d1f3bba070fb9de9375ffc61347504fb4e3aed903fbc073e65588de1207ed716e0e439bfa527d44ea13a28ba08f79ac025a0e42b683967ec1b"/*the signature*/);
console.log("address: "+recovered);//address: 0x627306090abaB3A6e1400e9345bC60c78a8BEf57

2023 answer.

import { recoverAddress, getBytes, hashMessage } from "ethers";
const recoverPublicKey = (message, signature) => {
    const digest = getBytes(hashMessage(message));
    return recoverAddress(digest, signature);

It is copied from here: https://www.ethsigpublicaddress.com/ that I assume uses ethers js version 6.

  • Link only answers are discouraged. It is better to include the code and main idea in the question and use the link to expand on the details.
    – Ismael
    Commented Sep 17, 2023 at 7:07
  • 1
    Changed to include the code itself
    – Shineli
    Commented Sep 18, 2023 at 8:20
  • Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.
    – Community Bot
    Commented Sep 21, 2023 at 12:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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