MehulBawadia's avatar

Laravel 5 password reset not working

I am working on laravel 5 eCommerce web portal.

I am having an issue when the user updates the password using the ready made scripts.

The issue is that I can send the link to the customer perfectly without any issue and the customer can change his password also. But when logged out and re-logging in, I get the error as Invalid credentials.

In my routes.php, I have this:

Route::controllers([
    'auth' => 'Auth\AuthController',
    'password' => 'Auth\PasswordController',
]);

This is the login page:

<form class="form-horizontal" role="form" method="POST" action="{{ url('/login') }}">
    <input type="hidden" name="_token" value="{{ csrf_token() }}">

    <div class="form-group">
        <label class="col-md-4 control-label">E-Mail Address</label>
        <div class="col-md-6">
            <input type="email" class="form-control" name="email" value="{{ old('email') }}">
        </div>
    </div>

    <div class="form-group">
        <label class="col-md-4 control-label">Password</label>
        <div class="col-md-6">
            <input type="password" class="form-control" name="password">
        </div>
    </div>

    <div class="form-group">
        <div class="col-md-4"></div>
        <div class="col-md-4">
            <a href="{{url('/password/email')}}">Forgot Password</a>
        </div>
    </div>

    <div class="form-group">
        <div class="col-md-6 col-md-offset-4">
            <button type="submit" class="btn btn-primary btn-block">Login</button>
        </div>
    </div>
</form>

When the login button is clicked on the login form page, the postLogin method is called. Here's the code

public function postLogin( Request $request ) {
    $this->validate( $request, [
        'email'     => ['required', 'exists:users,email,role,customer'],
        'password'  => 'required'
    ]);

    $credentials = $request->only('email', 'password');

    if ( \Auth::attempt($credentials) ) {
        \Session::flash('logged_in', 'You have successfully logged in.');
        return redirect('/');
    }

    return redirect('/login')->withInput($request->all())->withErrors(['email' => 'Invalid Email Address Or Password']);
}

I just realize that login is not checking for the hash and hence returning false, on doing dd(\Hash::check($request->password, $user->password)), after updating the password and re-logging in. What could be the issue with this ?

Where have I made mistake ? Kindly guide me.

Thanks in advance.

P.S.: I am using the defaults only to update the password, rest all, I have made the controllers and models which are all working fine without any issue.

0 likes
19 replies
procademy's avatar

Hello IamCrazyD,

We had the same problem and found out that we had a setPasswordAttribute function in our own User model which overrides the default save function. This save function had a different encryption (bcrypt) for the password

$this->attributes['password'] = bcrypt($password);

The password reset function is using this model to save the new password so it has not the original Laravel hashing method anymore, thus authentication will not work anymore. If you have a custom setPasswordAttribute function with hashing, please check this function. Perhaps this wil solve your problem as well.

One of our programmers included this setPasswordAttribute function based on this topic, so perhaps you did as well: https://laracasts.com/discuss/channels/requests/how-to-hash-user-input-password-when-using-form-validation-in-form-request-laravel-5?page=0

12 likes
yansusanto's avatar

I'm having the same issue too with L5.3

 public function setPasswordAttribute($password)
    {   
        $this->attributes['password'] = bcrypt($password);
    }

Adding that to User Model doesn't help with password reset. The user can reset, login & logout but thereafter logging in with the new password is validated as error.

richard's avatar

@yansusanto Huh!? Sounds weird. Try this:

dd ( bcrypt('raw_password') == "encrypted_password_in_db") and see if it returns true.

MehulBawadia's avatar

@yansusanto That is strange.. In my Laravel 5.3.* app, I have in the User model:

public function setPasswordAttribute($password)
{   
    $this->attributes['password'] = bcrypt($password);
}

I just tried to change the password, and re-logging in. It is completely working fine without any issue, on my end, at least.

Can you please show me the code of resetting the password.

yansusanto's avatar

I didn't not change anything as I'm using the default make:auth. Yes, you can reset & login.

But the same password is wrong when I try to relogin using the new one. I know it's weird when I don't change any code anywhere.

yansusanto's avatar

Well, in my case NOT having that code in my User model works, not sure why but it works without.

richard's avatar

@yansusanto try it on your web.php file (the routes files)

Route::get('test', function(){
    dd ( bcrypt('raw_password') == "encrypted_password_in_db")
})

What do get when you view it on the browser?

RobFrancken's avatar

I am also having this problem.

@richard

dd ( bcrypt('raw_password') == "encrypted_password_in_db")

won't work because password_hash() makes different hashes each time.

Instead, you should use

dd( Hash::check('raw_password', 'encrypted_password_in_db') );

My store method looks like this:

        $client = User::create([
            'first_name' => $request['first_name'],
            'last_name' => $request['last_name'],
            'email' => $request['email'],
            'password' => Hash::make($request['password']),
        ]);

I have also alternated between Hash::make() and bcrypt().

The Hash::check() method returns true.

Not sure why the password reset function is not working.

RobFrancken's avatar

I figured out what was wrong. I was missing the <input type="hidden" name="token" value="{{ $token }}"> field but because I was showing errors on individual form fields only (and not all errors) the token error wasn't showing up.

SUPAD's avatar

Well, i have the same problem but arrived to it on the other way : i started by setting the mutator on User and i also rewrote the reset method resetPassword in my own controller.

I don't get why the auth is not working anymore...

In my own controller, i have this :

protected function resetPassword($user, $password)
{
    $user->password = $password;
    $user->remember_token = Str::random(60);
    $user->save();
}

My mutator in User :

public function setPasswordAttribute($value)
{
    $this->attributes["password"] = \Hash::make($value);
}

In resetPassword,

\Hash::check($password, $user->password)

does send true.

But on the auth controller

\Auth::guard('web')->attempt(['pseudo' => $request->pseudo_login, 'password' => $request->password])

keep returning false...

SUPAD's avatar

Well... that's one of the embarrassing moment we wish we never have...

Password reseting is working very well, not my brain : i was trying to auth with my email while it's the login that i should send...

https://giphy.com/gifs/Ob7p7lDT99cd2/html5

vishnu17's avatar

I have made a custom reset password functionality and I was facing a similar issue with incorrect hash and invalid login, Thank you @esseremmerik , your answer just saved my day, I had spend a good 10 head-scratching minutes on this, bloody hell!

Robstar's avatar

For me the password reset form was working and generating a new password.

However, I was unable to login using the password I set. I'm sure there's a better fix than this, but here is my "solution". The issue was that the password being "bcrypted" twice - once by the Eloquent mutator on the user model and once via the "resetPassword" method at Illuminate\Foundation\Auth.

Override the method "resetPassword" in your own reset controller. Change it from:

protected function resetPassword($user, $password)
    {
        $user->forceFill([
            'password' => bcrypt($password),
            'remember_token' => str_random(60),
        ])->save();

        $this->guard()->login($user);
    }

to

protected function resetPassword($user, $password)
    {
        $user->forceFill([
            'password' => $password,
            'remember_token' => str_random(60),
        ])->save();

        $this->guard()->login($user);
    }

The other alternative would be to remove the mutator from the user model.

3 likes
rinth's avatar

I came across this just now. Thanks so much, Robstar! Your post helped me fix the issue by removing the hash from the password reset method.

dokohler's avatar

i run into the same problem. i also have my own password setPasswordAttribute-Method. I added a simple check, if the password is already a hash:

protected function setPasswordAttribute($value)
{
    // check if value is not empty
    if (!empty($value)) {

        // check if the value is already a hash (Regex: String begins with '$2y$##$' followed by at least 50 characters)
        if ( preg_match('/^\$2y\$[0-9]*\$.{50,}$/', $value) ) {
            // if it is so, set the attribute without hashing again
            $this->attributes['password'] = $value;
        }
        else {
            // else hash the password and set as attribute
            $this->attributes['password'] = bcrypt($value);
        }
        
        return true;
    }
    
    return false;
}
3 likes

Please or to participate in this conversation.