Skip to main content

How Laravel’s authentication system works

The Auth facade and AuthManager

The Auth facade proxies Illuminate\Auth\AuthManager. The manager uses a driver pattern to manage multiple guards and creates the appropriate guard instance based on config/auth.php.
resolve() reads the driver key from the guards array in config/auth.php and invokes the matching factory closure. The built-in session and token drivers use the same mechanism.

Guard vs StatefulGuard

Any authentication guard must implement at minimum Illuminate\Contracts\Auth\Guard. If the guard needs to maintain session state, implement StatefulGuard instead.
StatefulGuard extends Guard and adds methods for session and cookie-based login state.
Guards for API or token-based authentication typically only need to implement Guard because there is no session state to maintain. Guards that need session-based login (e.g. an admin panel) should implement StatefulGuard.

Implementing a custom guard

The GuardHelpers trait

The implementations of check(), guest(), id(), and hasUser() are nearly identical across all guards. Laravel provides Illuminate\Auth\GuardHelpers to handle them automatically, so you only need to implement user() and validate().

Building an API token guard

The example below follows the design of Laravel’s built-in TokenGuard. It reads a token from the Authorization header or a query parameter and resolves the user through the configured UserProvider.
1

Create the guard class

Place the guard class in app/Auth.
2

Register the guard in a service provider

Register the guard in the boot() method of AppServiceProvider using Auth::extend().
Auth::createUserProvider() reads the providers section of config/auth.php and returns the matching UserProvider instance. Unless you need a custom provider, this returns the standard EloquentUserProvider.
3

Configure the guard in config/auth.php

Add the new guard to the guards array.
4

Apply the guard to routes

Pass the guard name to the auth middleware.
To access a specific guard in controller code, use Auth::guard('api') or auth('api').

Closure-based request guards

Auth::viaRequest() lets you define a simple guard using only a closure — no class required. This is suitable for prototypes or very straightforward authentication needs.
Add the driver to config/auth.php:
Guards created with Auth::viaRequest() bypass the UserProvider entirely. Methods like retrieveById() will not be called. For production use, prefer a class-based guard registered with Auth::extend().

Custom UserProvider

When user data comes from a source other than the database — an external API, LDAP, etc. — implement Illuminate\Contracts\Auth\UserProvider.

Registering the custom UserProvider

Add the provider to the providers section of config/auth.php:
Wire the guard and provider together:

Practical example — separate guards for admins and users

1

Create the Admin model

The model must extend Authenticatable to integrate with the auth system.
2

Configure config/auth.php

3

Protect admin routes

Access the admin guard in a controller:

Authentication (basics)

Standard session-based authentication, starter kits, and route protection.
Last modified on March 29, 2026