Menu
Create Custom Side Menus
Frodo's Ghost | CakePHP :: Forgotten Password
37
post-template-default,single,single-post,postid-37,single-format-standard,eltd-core-1.0.1,ajax_fade,page_not_loaded,,borderland - frodosghost-child-ver-1.0.0,borderland-ver-1.2, vertical_menu_with_scroll,smooth_scroll,side_menu_slide_with_content,width_470,paspartu_enabled,paspartu_on_bottom_fixed,wpb-js-composer js-comp-ver-4.4.4,vc_responsive

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.

james
18 Comments
  • 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. 🙂

    July 7, 2009 at 4:35 am
  • 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?

    July 7, 2009 at 4:38 am
  • 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.

    July 14, 2009 at 5:15 am
  • 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!

    July 14, 2009 at 10:15 am
  • langis_sanda@yahoo.com
    Reply

    what if there’s no edit function? what if the password is hash?

    July 22, 2009 at 7:30 am
  • Actually it is because the passwords are hashed that we need the edit function. It is not secure to store un-hashed passwords.

    July 22, 2009 at 11:24 am
  • Nice trick dude. it helps me alot while creating forgot password page in my project. thanks for sharing it here.

    January 11, 2010 at 8:27 am
  • 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.

    February 23, 2010 at 10:41 am
  • Sorry about that, should now be fixed.

    Thanks for the heads up.

    August 12, 2010 at 12:33 pm
  • asli.amine@gmail.com
    Reply

    Thanks for the this exceptional tutorial.. keep going ! 🙂

    April 20, 2011 at 8:41 am
  • lthe3@student.monash.edu
    Reply

    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

    May 11, 2011 at 6:56 pm
  • 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.

    June 1, 2011 at 12:49 pm
  • 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?

    June 24, 2011 at 3:05 am
    • you have to add "Cookie" in components list:

      public $components = array(‘Paginator’, ‘Acl’, ‘Email’, ‘Cookie’);

      I also have couple others

      May 20, 2014 at 6:27 pm
  • Linda
    Reply

    Hi James!
    Your post is almost 3 years old – I recently used it and it helped me alot!
    Thanks for sharing!

    June 14, 2012 at 1:26 pm
  • Thnx That was helpful

    July 13, 2012 at 5:46 pm
  • Robert Gerculy
    Reply

    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.

    March 30, 2015 at 8:33 am
    • james@frodosghost.com
      Reply

      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.

      April 22, 2015 at 11:46 pm