›
byrcsc/laravel-dev-login · 1.x
What happens between clicking a button and landing on the next page, in the order it happens.
Clicking a profile button posts to dev-login.attempt. Four things then
happen, in this order:
The order matters at every step, and each step can stop the flow before anybody is authenticated.
ProfileRepository finds the profile by its route parameter and hydrates it
into a Profile. A parameter with no matching profile throws
ProfileNotFound, which lists the profiles that do exist.
Validation happens here rather than at boot. A typo in one profile is a readable exception on the page that needs it, not an application that will not start, and every message names the profile key.
The guard is checked against your own config/auth.php at this point, so a
profile naming a guard that does not exist or is not a session guard fails
before anything else runs.
A profile with no tenant skips this step entirely. An application with no
tenancy therefore behaves as though the feature were not there.
A profile that names one has its tenant handed to the configured
TenantResolver, exactly as it was written in config. String stays string,
integer stays integer.
This runs before the user is looked up, so the lookup happens inside the tenant. That ordering is what makes a tenant-scoped user provider find the right row.
If the resolver throws, the login stops here and nobody is authenticated. The
package wraps whatever your tenancy package threw in TenantNotResolved,
naming the profile and the tenant, and keeps the original as the previous
exception.
A profile that names a tenant while tenant_resolver is null also throws. A
button that cannot do what it says is worse than a button that is not there.
The UserResolver is chosen in this order:
resolver, if it names one.resolver key in config/dev-login.php.FindUserByEmail, the resolver the package ships.FindUserByEmail asks the profile's guard for its user provider and calls
retrieveByCredentials(['email' => $profile->email]) on it. Asking the guard
rather than a model or a config key is what makes custom user models, several
providers, and non-Eloquent providers work without any package configuration.
A resolver that returns null means the user does not exist, and the flow
stops with ProfileUserNotFound. The package never creates the user it cannot
find: it does not write to your users table.
The resolved user goes to SessionGuard::login($user, $profile->remember).
That call is Laravel's, not this package's, and everything that makes a real
login a login comes from it:
remember is true, the guard writes a remember token to the user and
sets the remember cookie. This is the one database write a dev login causes.Login and Authenticated events fire.A profile with fire_login_event set to false gets the same call with the
guard's dispatcher swapped for a null dispatcher, restored immediately
afterwards in a finally. The login is otherwise identical, because
reimplementing login() would produce a session that is only mostly a
session.
Clicking a second profile on the same guard replaces the first. There is no logout step.
The destination is the first of these that exists:
redirect.url.intended.default_redirect from config/dev-login.php./.A profile that names a tenant skips step two. A URL captured in one tenant rarely means anything in another.
web middleware group.TenantResolver contract has no matching
method, because nothing in the flow would call one.Authenticator is the class behind steps two through four. It takes a
Profile and returns the authenticated user:
use ByRcsc\LaravelDevLogin\Authenticator;
use ByRcsc\LaravelDevLogin\Profile;
$user = app(Authenticator::class)->login(new Profile(
key: 'admin',
label: 'Admin',
email: 'admin@example.com',
));It does not redirect, because the redirect is the controller's job. Use it from a test or from a console command of your own.