CakePHP :: Forgotten Password
Sometimes people forget. Usually it is when they need to get into their account or behind the nice ACL system you have setup. So, how do you handle the forgotten passwords?
With our sites we have a small form setup for people to fill in their email address, that will then send them an email with a replaced password, fill in the temporary password in the database, they then can use that new password to log in and change it.
The form in the view just asks for the email address of your blank-minded user. Since it is a user account interaction with the site we use the users_controller to run everything, thus this code goes into the views/users/forgot.ctp.
echo $form->create('User', array('action' => 'forgot')); echo $form->input('email', array('label' => '')); echo $form->end('Reset Password');
Next, add the forgot method to your in your users_controller. If we find an email in our database then we shall run the createTempPassword in our user model, Auth the resulting password and send a password.
function forgot() { if(!empty($this->data)) { $this->User->contain(); $user = $this->User->findByEmail($this->data['User']['email']); if($user) { $user['User']['tmp_password'] = $this->User->createTempPassword(7); $user['User']['password'] = $this->Auth->password($user['User']['tmp_password']); if($this->User->save($user, false)) { $this->__sendPasswordEmail($user, $user['User']['tmp_password']); $this->Session->setFlash('An email has been sent with your new password.'); $this->redirect($this->referer()); } } else { $this->Session->setFlash('No user was found with the submitted email address.'); } } }
There are two odd calls in here. The first we are calling $this->User->createTempPassword() – which is a method in the models/user.php. It looks something like this:
function createTempPassword($len) { $pass = ''; $lchar = 0; $char = 0; for($i = 0; $i < $len; $i++) { while($char == $lchar) { $char = rand(48, 109); if($char > 57) $char += 7; if($char > 90) $char += 6; } $pass .= chr($char); $lchar = $char; } return $pass; }
It returns a random string that we are saving into the users table. After that we are using the Auth component to set that string as a hashed value, that overrides that old password on Save. When we save it into the database, and everything goes smooth we run the Email Component -> which sends the email address an email.
First include the Email Component in the top of your users_controller.
var $components = array('Email');
And then in the same controller add the following code:
function __sendPasswordEmail($user, $password) { if ($user === false) { debug(__METHOD__." failed to retrieve User data for user.id: {$user['User']['id']}"); return false; } $this->set('user', $user['User']); $this->set('password', $password); $this->Email->to = $user['User']['email']; $this->Email->bcc = array('Your-Domain Accounts <accounts@your-domain.com>'); $this->Email->subject = 'Password Change Request'; $this->Email->from = 'noreply@your-domain.com'; $this->Email->template = 'users_'.$this->action; $this->Email->sendAs = 'both'; // you probably want to use both $this->Cookie->write('Referer', $this->referer(), true, '+2 weeks'); $this->Session->setFlash('A new password has been sent to your supplied email address.'); return $this->Email->send(); }
Done. Set the flash to inform the user of a sent out password. And a redirect back where they came from.
If you have another way to handle forgotten passwords in your sites, I would love to hear what you use, plugins or helpers to handle this kind of forgetfulness. Hit me up in the comments below.
crunchlabz@gmail.com
You could eliminate a step:
1. Click “I forgot my password”
2. Enter your username and a new password
3. Confirm new password via e-mail
This way you don’t have to login with a temporary password and then change it again.
I guess a problem would be if someone clicks “confirm” but didn’t request the new password himself, the other would have access to his account. You’re probably better off protecting people from their own stupidity. 🙂
jamesmonkey@gmail.com
Could do that. Most of the time though I use the email as the username. If that is the case all you need do is aquire someones username, and change their password.
The email does provide that sense of security.
Unless, on a second read, you confirm the new password in an email?
email@timcinel.com
Nice solution James, simple and elegant.
ElbertF’s idea is good but the email would need to stress the user NOT to click the link unless they requested a new password.
musa_bd@yahoo.com
it’s a good post but there is a chance of flooding/security hole. Let somehow anybody knew others email address, he can reset others password by submitting forgot password stuff. So password should be rest upon confirmation from email address. i think so!
langis_sanda@yahoo.com
what if there’s no edit function? what if the password is hash?
jamesmonkey@gmail.com
Actually it is because the passwords are hashed that we need the edit function. It is not secure to store un-hashed passwords.
snilesh.com@gmail.com
Nice trick dude. it helps me alot while creating forgot password page in my project. thanks for sharing it here.
jlebrech@hotmail.com
There’s a way to reset password by sending a ticket link rather than a new password, that way the email is confirmed, and the password is only changed once the user has recieved the email.
http://edwardawebb.com/programming/php-programming/cakephp/reset-lost-passwords-cakephp
btw your code is all showing up on one line.
jamesmonkey@gmail.com
Sorry about that, should now be fixed.
Thanks for the heads up.
asli.amine@gmail.com
Thanks for the this exceptional tutorial.. keep going ! 🙂
lthe3@student.monash.edu
Hi,i am following your tutorial on this[Forgot password] but now i have hit a block as i am lost on a certain area,i used everything you gave but i got this error:
Error: Database table users for model User was not found.
Please explain if you have ever found a way out of this one
jamesmonkey@gmail.com
Hi Lesego,
Not sure if you got this one solved. It looks like your model will need to be setup correctly – the User model is not pointing to the right table in the database.
If you are still stuck fire an email to james at frodosghost dot com with the code that is buggy and we’ll see if we can sort it out.
pine_rowan@yahoo.com
I want to ask you a question, I see on your code there is one line at __sendPasswordEmail function.
$this->Cookie->write(‘Referer’, $this->referer(), true, ‘+2 weeks’);
Is it your email was send has expridate? How about if the user read that email when it’s out of date?
lab@tonybla.de
you have to add "Cookie" in components list:
public $components = array(‘Paginator’, ‘Acl’, ‘Email’, ‘Cookie’);
I also have couple others
Linda
Hi James!
Your post is almost 3 years old – I recently used it and it helped me alot!
Thanks for sharing!
s.ramaninfinite@live.com
Thnx That was helpful
Robert Gerculy
Hi, I tried your script, but I have one problem, when I try to login it says invalid password.
Can you please help me out ?
Regards.
james@frodosghost.com
Robert,
Unfortunately I will need more information if I am to begin helping out. There could be some issues with the version of CakePHP you are using, because my code was from an old version.
I wouldn’t know where to start.