Search selfstore
v1.8.22

There is no password reset

A "forgot password" link is a statement about who holds the key. An app that encrypts on the client cannot offer one - so recovery has to be designed at the moment the password is chosen, not at the moment it is lost.

Every account you have ever made came with a way back in. Type your address, open a mail, choose a new password, carry on. The link is so ordinary that its absence reads as a missing feature.

It is not a feature. It is a consequence. A reset link can only exist because somebody other than you can already read your data, and is willing to hand it back once you have proved who you are. Move the key to the user and the link stops being possible, in the same breath and for the same reason that the breach stops being possible.

In a server-backed app, the password authenticates. It does not encrypt. The rows sit in a database the vendor can read - encrypted at rest, usually, under a key the vendor also holds, which protects against a stolen disk and against nothing else. Resetting is therefore easy: prove your identity by another channel, and the server, which never lost access, gives it back.

Client-side encryption changes the job of the password. Now it derives the key that turns the bytes into data, and it does so on the device. Nobody else has that key. There is no second channel that can produce it, no support ticket that can, and no amount of proving your identity that helps, because identity was never what the key was checking.

selfstore states it as a limit rather than a footnote: password recovery does not exist, and losing the password loses the encrypted backup. That is a promise, not a gap. Any library making the opposite claim is telling you where the key is.

Design the recovery before the password screen

The mistake is treating recovery as an error path. By the time someone is locked out, every option has already been decided. The decisions all happen earlier, and there is one structural choice that makes the rest possible.

Encrypt the data under a random key, not under the password. The corpus gets a data key that no human ever sees. The password derives a second key whose only job is to seal that data key - a few hundred bytes. This is key wrapping, and it is what lets an app have more than one way in: each unlocker seals its own copy of the same data key.

The alternative, deriving the corpus key straight from the password, quietly fixes the number of unlockers at one and makes every change a full re-encrypt. Apps that get this wrong do not discover it while the data is small.

With wrapping in place, three unlockers are worth offering, and they fail in usefully different ways:

Granting a device its own independent key is a real trade, not a free convenience: it widens what a stolen, unlocked laptop gives away. Worth doing deliberately, in that light, rather than because the fingerprint prompt looked nice.

Rotation is forward-looking, and files remember

Changing the password re-seals the data key on the copy you are holding. It does nothing to the copies you are not holding.

This matters most for backups, because a backup is a snapshot with its own key state baked in. A file written last March opens with last March’s password forever, wherever it currently sits - a USB stick, a cloud drive, a mail attachment. Rotating after a scare does not reach it. Some libraries let you re-key a file in place; selfstore exposes changePassword(blob, { from, to }) for exactly that, and it is per file by nature, which is the honest shape for the operation.

So the sentence a settings screen owes the user is longer than “password changed”. It is: new backups use the new password, files you already saved still open with the old one. If those old files matter, re-key them or delete them.

What the interface owes the user

The recovery that is not one

There is a design that looks like the best of both: the vendor escrows a copy of the key so support can help when things go wrong. It works. It is also, in precise terms, the server-side custody you left, with more moving parts.

One question settles which model an app is really running. If a court order arrived tomorrow, could the vendor produce readable data? If yes, the reset link is not a courtesy - it is a description of who holds the key, and any “zero-knowledge” wording on the marketing page is wrong.

An app that cannot reset your password is telling you something true. The cost is real, and it is paid by the small number of people who will lose data that nobody could have given back. The job is not to pretend that cost away. It is to make the loss require several unlikely things at once - a forgotten password, and a lost recovery code, and no enrolled device - instead of one forgotten string.


Try selfstore in five minutes, or read the other notes.