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);
}
}
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);
}
}
Alternatively, you can use the hashed cast:
class User extends Authenticatable
{
/**
* The attributes that should be cast.
*
* @var array
*/
protected $casts = [
'password' => 'hashed',
];
}
The `hashed`
cast was introduced in Laravel v10.