When I have accounts in my application, I handle passwords.
But everybody forgets the password. At least if you’re not working on a platform like Google, Microsoft or Facebook which uses the main authentication systems.
There is two types of users: those which use the same password for all the applications, and those which use a different password for each application.
The problem with the first group is that the password criteria is not the same for each application. Some ask for upper cases and lower cases. Other ask for digits. Other for a size higher than 10 characters. And some ask for special characters.
If the user use to handle a single password, when creating a new one, he will forget it quickly.
The second group of users, as they already manage a lot of different passwords, adding a new one won’t cause any trouble. They use to use applications like Keepass or the like to store all the passwords securely.
So, let’s focus on the first group. A user created an account one year ago, but doesn’t remember its password.
How to reset it?
Password Recovery Email
First of all, the user can only change its password to a new one. Never display the old password.
Why?
As a best practice, I must not store the raw password in my application. If my application has some security leaks, it’s all the user’s accounts which are compromised.
Second, am I sure that’s the same user who are requesting the password display? Won’t I display the password to another user?
So, the only option is to give to the user a form where to create a new password.
The user’s account must be associated to an email address. I must send to this email address a link to a password recovery page.

Password Recovery Form
What makes the password recovery email unique? When sending the email to the user’s address, the link to open the password recovery form must contain the ID of the user and a generated code.
This generated code must be associated to the user in the backend’s database. This way, a hacker won’t be able to reset the password by trying only the IDs of the users. The association of the user’s ID and the generated code must be correct to accept the new password.
Once the user choose a new password, the frontend sends to the backend the new password, the user’s ID and the generated code.
The backend only stores the new password if the user’s ID and the generated code correspond.
public void sendPasswordRecoveryEmail(User user) {
UUID uuid = UUID.randomUUID();
user.setCode(uuid.toString());
Message message = new MimeMessage();
// prepare email to be sent
String frontendPasswordRecoveryURL = "http://my-frontend/passwordRecovery?code=" + user.getCode() + "&user_id=" + user.getId();
// use the URL in the HTML of the email
Transport.send(message);
}
Generated Code Expiration
To ensure the email sent to the user is not used by an attacker, I have to limit the time the generated code is valid.
When generating the code in the backend, I must store the date and time when I’ve generated it.
And when receiving the new password, I ensure that the code is not expired. Let’s say the code is valid only 1 hour, or only 10 minutes.
The less time the code is valid, the smaller the windows is for an attacker to use the email’s link.
public void saveNewPassword(Long userId, String code, char[] newPassword) {
User user = userRepository.findById(userId);
if (user.getCode().equals(code)
&& user.expirationCode() > Instant.now()) {
user.setPassword(
passwordEncoder.encode(
CharBuffer.wrap(newPassword)));
}
}
Conclusion
The point with the password recovery workflow is that I must ensure that who updates the password is the real user.
That’s why I use the email address, because only the user has access to its email account.
And I add a generated code with an expiration date to ensure that the email sent is only used once and by the adequate user.



Leave a comment