Why email?

If you've locked yourself out of an account, there's no way to fix the state of a distributed database that would allow you to log in again. Luckily data recovery is still possible and starts by providing your email address when you create an account.

Email provides a way to verify ownership of your account code. Any verification method that is external to Gun would be fine, but email is the easiest to set up. Your email address was associated with your account code when your account was created. I shared some server code in an earlier post that stores your account data, but the actual code looks more like this:
 
app.post("/claim-invite-code", async (req, res) => {
  const encEmail = await Gun.SEA.encrypt(req.body.email, user._.sea)
  const data = {
    pub: req.body.pub,
    alias: req.body.alias,
    name: req.body.alias,
    email: encEmail,
    validate: encValidate,
  }
  user.get("accounts").get(code).put(data)
  validateEmail(req.body.alias, req.body.email, code, validate)
})
The first line in the function shows that your email address is encrypted when stored in Gun, it can only be accessed via the host account on the server. The validation code also needs to be encrypted, otherwise we couldn't prove that the validation request came from an email that was sent to you, since anyone would be able to create the link from data available in Gun.

Once your email is validated, if you ever need to reset your password then RSStream can send you a reset code. The reset code is stored under your account code in the host's account data, which also has your previous public key. Now when you follow the password reset link in an email, a new account will be created in Gun but the application has enough information to associate the old and new accounts. There is public data associated with your account that is not encrypted, that can also be copied over just by knowing your old and new public keys. What about private data though, is that lost along with your old account? Next we need to look at encrypted user data.

Help I've forgotten my password

Anyone who's worked on websites that allow accounts to be created has received this request for help. Many times. Unfortunately there's just no way to fix this problem in a distributed database. Accounts are literally public/private key pairs and the only way you can prove you have ownership over them is to provide a password that matches the correct decryption algorithm. In a traditional, server based web application you can hash the password provided by a user, compare it to a value stored in your database and provide them with a session token to use your application. In a distributed database, if you don't know the password that matches your key pair then you're locked out of your account.

I wasn't interested in working on a project where this was a blocker though, as it's too much of a requirement to put on user's that they can never reset a password. The answer was to come up with a workaround that looks like a traditional password reset to the user. What I'm using in RSStream works surprisingly well and I plan to use the same pattern in other projects that use Gun.

If a user forgets their password, you can't just replace the password hash in your database to fix the problem. You actually need to create a new account for them in Gun and migrate their data across. However now you have more problems. How do you maintain an identity when switching accounts? And how do you associate the old account with the new one?

The user can pick a username and password, but they will need to change both if a user has locked themselves out of their account. The process RSStream uses is to store their chosen username in the host's account data and then add a numerical suffix to it automatically if a password reset is required. The login screen hides this process by looping through the range of possible usernames and suffix, along with the new password until a match is found. (This is similar to what Gun does anyway, as usernames aren't guaranteed to be unique.)

As I mentioned previously, your account code is the main reference to your account in RSStream. Your username can change, but it's stored against this code which also has a reference to your previous public key. This allows data to be migrated when you next log in. Unfortunately, this really isn't enough for secure account migration, which is why we need to discuss email next time.