In many contexts, your application does not need a full "web3" provider, but just a way to identify the user's address. Unlock offers a flow that allows any application to easily identify the user by requiring them to sign a message. For this, we use a flow that's based on the EIP 4361 and that's inspired by the OpenId Connect and OAuth flows where the user is redirected back to the application once they have authenticated.
"Ethereum" here does not refer to any network in particular but to the type of wallet that can used. Since Polygon, Gnosis Chain or Optimism for example are all using the same wallet, you can (should!) absolutely use the same "Sign In with Ethereum".
By using Unlock's "Sign-In with Ethereum", users who do not have a crypto wallet can also easily create an Unlock Account, as well as sign in to their existing account with their email and passwords.
Building a "Sign-in With Ethereum" URL
Your application just needs to build these URLs using the following:
Required query parameters:
redirect_uri: the URL toward which the user is redirected once they have connected their wallet and signed the message to authenticate them
client_id: a string to identify your application. It MUST match the "host" part of the
Optional query parameters:
paywallConfig: a JSON object built using the same structure in purchase URLs. You can customize the
iconelements in particular.
If the user refuses to connect and/or sign a message in their wallet, they will be redirected back to the
redirect_uri and a new query string parameter will be attached
If the user connected their wallet and signed the messages, they will also be redirected to your application, this time with a
code extra query parameter. The value of this parameter is base64 encoded and can be decoded by your application in order to retrieve the signature message along with the message that was signed. Using these 2 values, you can "recover" the address of the signer.
Most Ethereum libraries include a function to compute the signer's address from a message and the corresponding signature:
const urlSearchParams = new URLSearchParams(window.location.search);
const params = Object.fromEntries(urlSearchParams.entries());
const code = JSON.parse(atob(params.code));
// The code object has 2 properties:
// d: digest (the signed string)
// s: signature (the signature)
const address = ethers.utils.verifyMessage(code.d, code.s);
Example of message signed:
ouvre-boite.com wants you to sign in with your Ethereum account:
Issued At: 2022-02-04T18:43:17.178Z
The signed message includes both a timestamp AND a random nonce that your application should leverage to increase the level of confidence that a user's authentication is both recent and "unique". By parsing the signed message your application can extract the following information:
domainof the application to which the user will be redirected. Your application should ignore any signed message where the host does not match your application.
Noncethis is a randomly generated sequence of 8 alphanumerical characters. The collision risk is extremely low, which means that your application should refuse any message with a nonce that's previously been recorded
Issued At: this includes a timestamp in the iso8601 format. Your application should ensure that this timestamps is very recent (within seconds in the vast majority of cases).
Finally, your application may want to take into account the address signed in the message, rather than the actual signer of the message itself as the actual identifier for the account. This is especially useful in the context of smart contract wallets where the signer needs to be an "authorized" signer on the contract. (See EIP 1271 for more details)