Validate Existing Password when Changing Password in CakePHP 4

Validate Existing Password when Changing Password in CakePHP 4

This post explains how to allow a user to change their password, validating their current password first.

Note, we are using Cake\Auth\DefaultPasswordHasher to handle our password hashing.  This tutorial does not include field validation for password and confirm password; Only validating existing password is covered.

First, we need a form / template to change passwords:

Template /templates/users/changepassword.php

echo $this->Form->create($user);
echo $this->Form->control('current_password', ['type' => 'password', 'required', 'class' => 'form-control', 'label'=>'Current Password', 'id'=>'old-password']);
echo $this->Form->control('password', ['type'=>'password', 'required', 'class' => 'form-control', 'value' => '', 'label'=>'New Password', 'id'=>'new-password']);
echo $this->Form->control('confirm_new_password', ['type' => 'password', 'required', 'class' => 'form-control', 'label'=>'Confirm Password', 'id'=>'confirm-new-password']);
echo $this->Form->submit('Update password', array('class' => 'btn btn-primary'));
echo $this->Form->end();

Next, we need a function in the controller to handle the form and saving the password:

public function changepassword() {
   $user = $this->getRequest()->getSession()->read('Auth');
   $user = $this->Users->find('all', ['conditions' => ['Users.id' => $user['id']]])->first();
   if ($this->request->is(['patch', 'post', 'put'])) {
       $user = $this->Users->patchEntity($user, $this->request->getData() );
       if ($this->Users->save($user)) {
           debug('success');
       } else {
           debug($user->getErrors());exit;
       }
    }
}

Next, check your User.php file to ensure your password field isn't hidden

in src/Model/Entity/User.php file, remove or comment this out.

protected $_hidden = [
        'password',
    ];

Also in the src/Model/Entity/User.php file, make sure your password is listed as true in the protected $_accessible section

'password' => true,

Next set your validators to handle validation of the existing user's password

in the src/Model/Table/UsersTable.php file, add the following validator:

$validator
    ->notEmpty('current_password')
    ->add('current_password', 'custom', [
        'rule' => 
            function($value, $context) {
               $query = $this->find()
                    ->where([
                        'id' => $context['data']['id']
                    ])->first();
               $data = $query->toArray();
                   return (new DefaultPasswordHasher)->check($value, $data['password']);
                    },
                    'message' => 'Current password is incorrect!'
            ]);

 

That should do it.  Now, when you use the above form to change the user's password, it will validate the existing password before saving, and if incorrect, will throw an error (debug shown here, so you can format to your taste).

Share this Post