›
›
›
  1. docs
  2. ›
  3. byrcsc/laravel-dev-login
1.x
Browse documentationOpenClose

Getting started

  • Introduction
  • Installation and setup
  • Quick start

Core concepts

  • Profiles
  • Safety gates
  • The login flow

Extending

  • User resolvers
  • Tenancy
  • Routes and redirects
  • Customizing the page

Reference

  • Configuration
  • Testing
  • Troubleshooting

Getting started

  • Introduction
  • Installation and setup
  • Quick start

Core concepts

  • Profiles
  • Safety gates
  • The login flow

Extending

  • User resolvers
  • Tenancy
  • Routes and redirects
  • Customizing the page

Reference

  • Configuration
  • Testing
  • Troubleshooting

byrcsc/laravel-dev-login · 1.x

The login flow.

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:

  1. The profile is read from config and validated.
  2. Its tenant is made current, if it names one.
  3. Its user is resolved.
  4. The session guard authenticates that user, and the response redirects.

The order matters at every step, and each step can stop the flow before anybody is authenticated.

1. Reading the profile

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.

2. Making the tenant current

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.

3. Resolving the user

The UserResolver is chosen in this order:

  1. The profile's own resolver, if it names one.
  2. The resolver key in config/dev-login.php.
  3. 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.

4. Authenticating

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:

  • The session ID regenerates, so a fixation attempt on the previous ID is worthless.
  • If 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.
  • The 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.

5. Redirecting

The destination is the first of these that exists:

  1. The profile's own redirect.
  2. The session's intended URL, pulled from url.intended.
  3. default_redirect from config/dev-login.php.
  4. /.

A profile that names a tenant skips step two. A URL captured in one tenant rarely means anything in another.

What the flow never does

  • It never authenticates anything itself. Every session comes from Laravel's session guard.
  • It never checks a password. No password is read, compared, or written.
  • It never writes a user. The only write in the flow is the remember token Laravel's guard writes, and only for profiles that asked for it.
  • It never logs in by GET. There is no GET route that authenticates, because a GET that logs you in can be fired by an image tag or a prefetch. The POST route is CSRF-protected by the web middleware group.
  • It never ends tenancy. The TenantResolver contract has no matching method, because nothing in the flow would call one.

Driving the flow directly

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.

What to read next

  • User resolvers to change how step three finds a user.
  • Tenancy to implement step two.
  • Routes and redirects to control step five.
PreviousSafety gatesNextUser resolvers
View source

On this page

  1. 1. Reading the profile
  2. 2. Making the tenant current
  3. 3. Resolving the user
  4. 4. Authenticating
  5. 5. Redirecting
  6. What the flow never does
  7. Driving the flow directly
  8. What to read next