When building a website with sign up / login, we have to build a feature that allow user to reset his password if he forgot it. There are many technical ways could do this. But I am gonna show you a better way to do this in elegant user experience and less code lines.
USER EXPERIENCE
- User forget his password, and clicked password reset link
- Show user a form to let him input his email address
- User get an Email in his inbox containing a reset password link ( link will expire in 1 hour )
- User go to that link, enter new password for his account
Regarding user experience, it is nothing new because most websites do it like this.
HOW TO DESIGN BACK-END
- After user enter his email address in reset password form, validate this email in database. If valid, get the user _id
- Encrypt the userid with timestamp and a secret string ( let's call the secret string KEY ) to get the HASH string. for example: HASH = MD5 ( userid + timestamp + KEY )
- Send an Email to user's email address containing a reset password URL with HASH parameter and other needed information. for example: http://domain.com/reset-password.php?hash=HASH&user_id=123×tamp=1392121211
- When user arrives the reset password page, we get the hash parameter, userid and timestamp. Now, we need to verify the parameters by checking if HASH == MD5 ( userid + timestamp + KEY), which KEY is a pre-defined value in back-end server
- Then, we need to check the timestamp to determine if this link is expired
- If all validation passed, show user the reset password form
In this new way:
- we do not need any new database tables
- parameters in reset password link are safe, if user change the user_id or timestamp, he will not pass the validation
- reset password link contains timestamp to verify expiring
- it is safe enough if we use a long string for KEY, because MD5 is a one-way encryption
Here are some code to help you understand the idea better:
send-reset-email.php:
$KEY = "something really long long long long long and secret";
$email = $_POST['email'];
$user = get_user_by_email($email);
if ($user && $user['id'])
{
$time = time();
$hash = md5( $user['id'] . $time . $KEY);
$url = "http://domain.com/reset-password-form.php?id=".$user['id'].'×tamp='.$time.'&hash='.$hash;
send_email($email, 'reset password email from xxx.com', ' Please click the following link to reset password'. $url);
}
reset-password-form.php:
$KEY = "something really long long long long long and secret";
$hash = $_GET['hash'];
$user_id = $_GET['id'];
$timestamp = $_GET['timestamp'];
if ($hash == md5( $user_id . $timestamp . $KEY ))
{
if ( time() - $timestamp > 3600 ) // one hour
{
die('link expired');
}
}
else
{
die('invalid parameters');
}
//validation passed
if ($_POST['new_password'])
{
reset_user_password($user_id, $_POST['new_password']);
die(' password changed successfully ');
}
else
{
echo '
<form action="reset-password-form.php?hash=$hash&id=$user_id×tamp=$timestamp" method="post">
new password: <input type="password" name="new_password">
<input type="submit" value="submit">
</form>
';
}
The code above is not runnable, it's just an idea to help you understand better. Hope you can enjoy it :)
-- END --