Authentication

How to authenticate with MetaMask

graphical divider

Authentication instructions

Background

This site implements user authentication via Ethereum private keys, through a browser-based wallet extension like for example Metamask. This should be very much understood as a minimum viable product, if that, and it is very much work in progress. So if MetaMask pops up and is asking you for a signature, then this is probably not someone trying to steal your NFTs. Having said this, it is better to be safe than sorry in this respect, and you should always know what you are signing. In this case the only thing the site will ever ask you to do is to sign a message; it will not send funds or call smart contracts methods. In other words, all you every see from this site are instructions of the form

metamask screenshot

ie messages that say “Please sign ‘please-sign-to-login-[some-numbers]'”. Why do we need this? Easy – the site needs to verify that you are the owner of a specific address. To prove this you need to show you know the private key, and the easiest way to show is by signing a message.

The only complication is that if you want to prove it to me, then I must choose the message you sign, and I also need to make sure that you do not have access to previously signed messages. This is why we have a nonce, ie the numbers towards the end of the message and that should never repeat. The remainder is just to make you feel better, and to make sure that those numbers to not have a hidden meaning like signing a hash.

Token-based permissioning

In this site we are trying out token-based permissioning, ie that tokens that you hold in your wallet determine what permissions you have. For this we have created a permissioning contract which is a normal ERC20 contract, and you have full access to the site if an only if you hold the token.

I am saying full access here because we can think about a hierarchy of access restrictions, along the lines of

  1. Everyone (no restrictions)
  2. Metamask-provided addresses
  3. Verified addresses (signed challenge)
  4. Ditto holding minimum fund levels
  5. Ditto holding dedicated permission tokens

The most important distinctions here are 1 (public), 3 (verified address) and 5 (access token) but 2 can be a quick and dirty way to establish some ressemblance of identity, and 4 ensures that the address is not entirely throwaway. In particular there may always be a possibility linking it to a real world identity using chain analysis techniques.

How does it work?

Connect to the BSC Testnet

Firstly may I suggest you use a throwaway wallet for this exercise: create a new Chrome profile, install the Metamask extension, and create a new throwaway account, using throwaway1 or something like this as password so that you remember not to use the account for anything serious.

Next, connect MetaMask to the Binance Smart Chain Testnet. The key parameters to do this are as follows:

  • Network Name: BSC Testnet
  • Chain ID: 97
  • RPC URL: https://data-seed-prebsc-1-s1.binance.org:8545/
  • Block Explorer: https://testnet.bscscan.com

Finally you should head over to the faucet and get some free coin.

Get access tokens

At the moment the only way to get tokens is to get them from someone who has them. Ping me on Twitter (I am @odtorson) and I send you one.

Connect your wallet and sign a message

Context

The UX of the process is still a bit rough around the edges, but (a) reloading the page, and (b) clicking logout and disconnect should generally sort out any weird states and reset the system to work correctly. The issue is, as so often, cache invaliation: in an ideal world we’d just have every message signed with the private key and that’s it. However, because this requires human interaction every time this is not an option, so we need to cache state. Likewise, verification of token ownership takes a noticeable amount of time so can’t be done at every request either

Specifically, the server keeps track of tokens and their associated verified addresses. Those tokens are not particularly safe – anyone with a token can use it – so they are relatively short lived. This also solves the issue of token transfers: ownership is currently only checked at every token renewal.

Those are the big issues. There are also small ones, related to the fact that there are quite a few different states to consider (no meta mask installed, not connected, not signed etc) and we have at least 4 storage locations (the server, the JavaScript engine, the UI, the browser local storage/cookies). So things can get out of synch easily – hence the suggestion to start from a clean slate when this happens and reload.

The Process

Currently the process of getting access to the site is a three step process

  • Wallet set-up. Connect the wallet to the correct network and authorize it to interact with the site

  • Token acquisition. Acquire the necessary permission token and place it in the decicated wallet; you may also have to configure the wallet to recognise the token even though this is only a UX issue - the system does not require it

  • Signature. Sign the challenge issue be the server whenever needed

This sounds more complex than username/password, but this is mostly due to the fact that our tools (Metamask, cough) are not optimised for the task at hand. In an ideal world we’d be using a dedicated extension sporting optimized processes for what we are trying to do. But even here is is actually fairly straight forward: from time-to-time the Metamaske “sign here” dialogue will pop up, the user needs to click, and that’s it. The main risk is get people used to automatically approve transactions on Metamask which may not be a good idea, because of the phishing opportunities this offers.

In practice the process to log in is as follow: first press on connect and allow Metamask to connect to the site. Then click login and sign the challenge in Metamask. If you click logout you effectively revoke the signature, and disconnect removes (or rather, ignores) the connection to Metamask.

And remember - the signature screen looks like this: the message always starts with please-sign-to-login and ends with a nonce