In an earlier tip, I explained why Laravel offers a max password length rule. Bcrypt only uses the first 72 bytes of a password and silently ignores the rest, so it's better to reject a long password up front.
That advice still stands, but it has a gap.
The max rule counts characters, not bytes.
Under the hood, Password::max(72) uses mb_strlen(), while bcrypt counts raw bytes.
For plain ASCII, those are the same number, but the count is not the same for accented letters or emoji.
So a password with accented letters can pass max(72) and still get truncated by bcrypt.
Laravel doesn't have a built-in rule that counts bytes on a regular string.
But the Password rule lets you add your own checks with rules(), and you can register the whole thing once with Password::defaults().
// in AppServiceProvider::boot()
Password::defaults(function () {
return Password::min(8)
->rules([
function (string $attribute, mixed $value, Closure $fail) {
// purposely using this function to count raw bytes, not characters
if (strlen($value) > 72) {
$fail('The :attribute is too long.');
}
},
]);
});
Now every password field uses the same rule.
'password' => ['required', 'confirmed', Password::defaults()],
Here to help,
Joel
P.S. Silent defaults like this are easy to miss until they bite. Our security book helps you spot the ones worth changing in your app.