MetaMask – Authenticating with an Ethereum Account through personalSign

authenticationmetamasksignatureweb3-providers

I want to authenticate a user using her Ethereum account. There are several demos and tutorials available, for example Amaury's which uses, however, the deprecated web3 API:

web3.personal.sign(web3.fromUtf8("Hello from Toptal!"), web3.eth.coinbase, console.log);

MetaMask no longer injects web3. For details, see: https://docs.metamask.io/guide/provider-migration.html#replacing-window-web3

Uncaught TypeError: web3.personal is undefined

I'm using the new window.ethereum directly, which works well to connect to a wallet provider and retrieve accounts, e.g.:

const accounts = await ethereum.request({ method: 'eth_requestAccounts' });

However, it does not really expose eth_personalSign as suggested in the MetaMask docs:

  • eth_sendTransaction
  • eth_sign (insecure and unadvised to use)
  • eth_personalSign
  • eth_signTypedData
const sig = await ethereum.request({ method: 'eth_personalSign', params: ['0x0', 'foo'] });

MetaMask – RPC Error: The method 'eth_personalSign' does not exist / is not available.

How to authenticate with an Ethereum account through personalSign?

I experimented with eth_sign instead, which at least goes through to the web3 provider and allows me to sign a message in MetaMask. But it is cumbersome to handle and does only return a forever pending promise…

Best Answer

It's personal_sign now, not eth_personalSign. It has always been personal_sign, it's probably just a typo in the Metamask docs.

const message = "Hello from Ethereum Stack Exchange!";
const accounts = await ethereum.request({ method: 'eth_requestAccounts' });
const account = accounts[0];
const signature = await ethereum.request({ method: 'personal_sign', params: [ message, account ] });
Related Topic