In this article, I outline a system for password resets which avoids relying on email, while still maintaining interesting security properties ensuring only the person whose account it is can reset their password.
In the beginning of this year I released a forum software, Cerca, which is the engine driving the nascent Merveilles community forum. As is typical of many forumsofts, users register accounts secured with passwords—all so that only the creator of the account can post under their name or delete their posts. And as is typical of users and passwords, there will inevitably be people for whom the need will arise of a resetting their password: because they’ve lost the old one, they forgot to save it in the first place, etc.
I was thinking about this conundrum, about what mechanism to employ for account retrieval, when laying out the software. One thing I felt rather strongly about was wanting to avoid introducing email as a required subsystem.
I mean, email’s a no-brainer right? Everyone’s got an address, practically all services use it in some way or another—some skipping passwords altogether in preference of emailing so called magic links, which log a user in after clicking the email’s link. What’s up with feeling so strongly about wanting to avoid it in my own software?
Well, one of the goals of Cerca is to keep the deployment and maintenance feasible for very lean computing setups, and little time investment. Once you bring email into the fold you suddenly have this big, unwieldy system you have to ensure works continually. Email is also a system in which failures are insensible—breakages are not immediately apparent. What I mean is, if the posting functionality breaks in the forum you would notice that very quickly. If the rendering breaks, same thing. But if email breaks, and people aren’t receiving their password reset links then… that’s not immediately apparent from everyday use of the forum.
Typically, to make email consistently operational, most softwares outsource the burden. Often used are services like Sendgrid, Mailgun, whatever. So, now you have an external service which always needs to be reachable (and not get bought up and shut down), an extra API interface to take into consideration, and potentially bills which need to be paid. Dreadful. On the other side of the spectrum, self-hosting email is it’s own full-time endeavour:
The other issue with artisanal email systems is that the organization needs people who can run them, and those people have to spend time on email; generally the better and more artisanal a system you want, the more time it takes.
Another reason to avoid email is that email addresses are one of the most valuable identifiers in use today. They tie one identity across a multitude of platforms, and typically are what’s used to secure access to the same plethora of platforms (practically all services use email, remember?)
If you don’t collect email addresses, you’re…
Lastly: who needs more emails??
There was a need for resetting passwords, and using emails was out of scope. I was also looking to employ an automated system, so as to decrease the load on the system administrator.
What I ended up going with was generating a set of information during the account registration process. This information, when used, could verify the veracity of reset requests with respect to the account in question. Put in other words, I made use of public-key cryptography.
In brief, public-key cryptography (or asymmetric cryptography) is a set of mathematical properties which can be used to great effect in computer systems. It’s used in the browser certificates that keep your transaction requests private to their final destination, and in newer paradigms of group chats and social networks (like Cabal and SSB).
There are two pieces of information: the public key, and the private key. When held together the couplet is known as a keypair. The public key can be shared in public as much as one desires. The private key is to be kept private.
The public key is used to identify the identity holder, to encrypt information to the holder, or verify statements made by the holder. The private key, inversely, allows the holder to decrypt information intended for them, and to create statements which only they could have created.
This is how everything is tied together:
When someone registers an account, the forum generates a keypair for them. They are told to hold on tight to the keypair, as only the public portion is saved in the database.
Later, when that someone’s forgotten their password, they visit the password reset form and we generate a bit of text for them (called the proof payload). Using the payload, the keypair received during registration, and a dedicated program, a password proof is created.
After generating the password proof, it is passed back to the reset form. The form is submitted and the forum verifies the proof by looking up the associated public key for the requesting user and uses that, together with the proof payload and the proof, to cryptographically verify the request.
If the proof was valid and the request verified, the initial generated text is saved to the database. This is done to decrease the likelihood of some third party reusing a generated proof to reset the user’s password.
When all this is done, the user can now log back into the forum using the new password they set!
Instead of having one thing a user needs to keep track of, there are now two. That could seem a bit backwards, but maybe that’s an acceptable trade-off for avoiding to collect someone’s email?
The generated keypair can be kept in a multitude of ways until needed: stored in a plaintext file or a password manager, printed out, or as a screenshot.
One might also think:
“Well, if you’re going to generate a keypair anyway, why not just use that to login?”
The reason being that people can choose a password they can remember and use across devices: on a desktop computer, through their password manager, and on their phones when bored on-the-go. Using a regular password requires less up-front education than the keypair equivalent, where the education only enters the picture when the user is motivated to reset their password.
Wrapping up: this way of solving the problem of password resets is fun to implement and relatively straightforward using existing cryptographic primitives available in many programming languages. The solution shouldn’t pose any greater maintenance challenges going forward and, as far as I know, it’s a novel approach.
Have a look at the implementation in Cerca, and if you find my work interesting you can join others in crowdfunding it.
After publishing this article, I received quite a few interesting responses and reactions! I decided to list some of those here as an appendix of sorts, in case others were interested. Some of the solutions are more complex or less generally applicable than others, but they all have in common that they are ways of solving the problem of password resets without having to rely on email.
So! Here are some other email-less alternatives for password restoration, listed roughly according to feasibility for the forum use case:
For each user, generate a block of one time codes that they can use to reset their password. As noted from the name, the code when used cannot be reused.
A second high-complexity password is generated on account creation, and presented to the user. If they lose or forget their primary password, they can use this secondary password to reset it. The secondary password is only used for resetting.
Depending on your usecase, your users may already have existing keypairs, such as is used for ssh, attached to the account. If they lose their primary password, but they maintain their ssh keypair, a similar challenge-response mechanism as is outlined above can be used to prove that the holder of the ssh keypair can reset their account’s password.
Two-factor hardware solutions and authenticator applications are increasingly common in some spheres, and there are open protocols (such as FIDO2) which can be implemented in one’s service such that a two-factor authentication mechanism can be put into place. If the user loses their primary password, they could use their FIDO2 authenticator as an authentication mechanism during a password restoration process.
Thanks to Ramsey Nasser, Piggo, cascode, Atsuko Ito, and danny.page, and Alex Schroeder for the feedback and suggestions!