DEV Community

Mahmoud Ramadan
Mahmoud Ramadan

Posted on • Edited on

Rehashing Passwords on Login

I encountered a strange scenario while adding a feature to the Admin Dashboard.

The problem was that I had a mutator method in my model for hashing the password:

use Illuminate\Support\Facades\Hash;

/**
 * Set the model password attribute.
 */
public function setPasswordAttribute($value): void
{
    if (!empty($value)) {
        $this->attributes['password'] = Hash::make($value);
    }
}
Enter fullscreen mode Exit fullscreen mode

Later, while logging into the admin dashboard using a simple password (since it was on the local stage), I discovered something odd: the password was being updated after I logged in. This happened because the input password was passed through the mutator again, causing it to be re-hashed.

To test further, I manually hashed a strong password using Tinker and attempted to log in again. Surprisingly, this time the request didn't go through the mutator.

I then looked into how the attempt method works, which in turn uses the rehashPasswordIfRequired method, which internally relies on the needsRehash method. That method checks if the given password hash needs to be rehashed, depending on the hashing value, the used algorithm, and other options.

The rehashPasswordIfRequired and needsRehash methods have been available since Laravel v11.

The mutator was hashing passwords in multiple places, which makes it difficult to track. Removing the mutator would require manually hashing passwords wherever they're set.

Then I discovered the isHashed method, which checks whether a value has already been hashed. It helped me avoid rehashing values that Laravel had already processed internally:

/**
 * Set the model password attribute.
 */
public function setPasswordAttribute($value): void
{
    if (!empty($value) && !Hash::isHashed($value)) {
        $this->attributes['password'] = Hash::make($value);
    }
}
Enter fullscreen mode Exit fullscreen mode

Alternatively, you can use the hashed cast:

class User extends Authenticatable
{
    /**
     * The attributes that should be cast.
     *
     * @var array
     */
    protected $casts = [
        'password' => 'hashed',
    ];
}
Enter fullscreen mode Exit fullscreen mode

The hashed cast was introduced in Laravel v10.

Top comments (0)