Skip to main content

Timing

An answer can read the same and still tell the caller which case it was, by how long it took. A password is stored as a bcrypt hash, and at Laravel's default cost of 12 rounds one hash takes in the order of a quarter of a second. Whichever answer pays for a hash that the other one does not is that much slower, and a single request shows it.

Registration​

Creating an account hashes its password, and finding a taken address does not. Without the package a taken address is answered in a fraction of the time a free one takes.

The package has both outcomes pay the same hash. On Fortify's route your CreatesNewUsers action hashes the password of a new account, and for a taken address the package hashes the same password with the same hasher. The registrar hashes the password once, before the address is looked up, and hands the hash to the code that creates the account.

Both outcomes also send one mail: the verification mail of a new account, or the notice to the holder of a taken address. Send them the same way. Laravel sends the verification mail at once, and so does the package's notice; an application that queues the one queues the other, as shown in Registration.

The minimum duration​

The password routes work the other way round. For an address with an account the broker creates a token, which costs a hash, and sends the link; for an address without one it does neither. Laravel holds these requests, and a failed sign-in, to a minimum duration called a timebox, so that the short case waits until the long one would be done. Its default is 200 milliseconds, which is less than the hash alone, so the case with an account still takes longer.

The package raises that minimum to one second by setting auth.timebox_duration, unless your application sets that key itself. A failed sign-in, every reset-link request and a failed reset then take one second, with an account or without. A successful sign-in and a successful reset still return at once.

SettingDefault
timebox.microseconds1000000, one second
FORTIFY_HARDENING_TIMEBOX_MICROSECONDSthe same, from the environment

Set it to 0 to leave Laravel's own minimum in place. A value of your own in auth.timebox_duration always wins over the package's.

The minimum only hides work that finishes inside it. Queue the reset-link notification, so that sending the mail is not part of the request, and keep the minimum above the time your slowest server needs for one hash.