In Laravel's config/auth.php, what is the difference between a guard and a user provider, and what ships by default?
answer
- how vs where
- guard: driver plus provider name
- web guard uses the session driver
- users provider: eloquent, App\Models\User
- defaults.guard reads AUTH_GUARD, falls back to web
basics
~20 sA guard decides how a request is authenticated and remembered; a user provider decides where user records are loaded from. The Laravel 13 skeleton ships one web guard (session driver) pointing at one users provider (eloquent, App\Models\User).
solid answer
~40 sIn `config/auth.php` a **guard** is the component that works out who is making the request: the Laravel 13 skeleton defines a single `web` guard with the `session` driver, so the signed-in user's ID is kept in the session between requests. A **user provider** is the storage side: given an ID or a set of credentials, it loads the user. The skeleton's `users` provider uses the `eloquent` driver with `'model' => env('AUTH_MODEL', User::class)`; a commented-out block shows the `database` driver with a `table` instead. Each guard names its provider through its `provider` key, and `defaults.guard` (`env('AUTH_GUARD', 'web')`) chooses the guard that `Auth::user()` and `$request->user()` use when you name none. Packages plug extra guard drivers into the same file: Sanctum registers `sanctum`, Passport registers `passport`.
go deeper
Recall the pair: a guard answers how the request is authenticated, a provider answers where users are loaded from. Know the skeleton's web, session, users and eloquent values.
Explain the lookup chain from defaults.guard to the guard's provider key to the model, and why session guards are stateful while token-style guards re-check every request.
Show you can read an unfamiliar config/auth.php and say which guard each route family uses, which provider backs it, and what breaks when a package adds its own driver.
Argue when a second guard is warranted versus one guard with roles, and how the split keeps transport and storage decisions independent as the product grows.
## Two separate questions Authenticating a request in Laravel means answering two different questions, and `config/auth.php` gives each one its own component: - **How do we know who this request belongs to?** That is the job of a **guard**. A guard inspects the request (a session cookie, a header, a query parameter) and returns the user, or `null`. - **Where do user records live, and how do we load one?** That is the job of a **user provider**. A provider knows how to fetch a user by ID, by credentials such as an email address, or by a "remember me" token, and how to check a password against the stored hash. Keeping them apart means you can change the transport (session versus token) without touching the storage, and change the storage (an Eloquent model versus a plain table) without touching the transport. ## What the Laravel 13 skeleton ships A fresh `laravel/laravel` 13 application has one of each: | Key | Value in the skeleton | Meaning | |---|---|---| | `defaults.guard` | `env('AUTH_GUARD', 'web')` | guard used when code names none | | `guards.web.driver` | `session` | user ID stored in the session | | `guards.web.provider` | `users` | which provider loads the user | | `providers.users.driver` | `eloquent` | load users through a model | | `providers.users.model` | `env('AUTH_MODEL', User::class)` | the model class | The file also carries a `passwords` section for the password broker and `password_timeout`, which belong to the reset and confirmation features rather than to guards. The skeleton's `.env.example` sets none of the `AUTH_*` variables, so the fallbacks above are what runs. ## How one request uses them 1. Code calls `Auth::user()`, `auth()->user()` or `$request->user()` without naming a guard. 2. The auth manager (`Illuminate\Auth\AuthManager`) reads `defaults.guard`, finds `guards.web`, and builds a `SessionGuard` the first time it is asked, caching it for the rest of the request. 3. While building the guard it creates the provider named in `provider`, here an `EloquentUserProvider` for `App\Models\User`. 4. The session guard reads the user ID from the session and asks the provider for `retrieveById($id)`. 5. The provider runs the model query and returns the user, which the guard caches. Name a guard that is not in `guards` and `Auth::guard('x')` throws `InvalidArgumentException` with the message "Auth guard [x] is not defined." ## Session versus token drivers Guard drivers fall into two families: - **Stateful** guards implement `Illuminate\Contracts\Auth\StatefulGuard`. The built-in `session` driver (`SessionGuard`) is the only one in the framework: it has `attempt()`, `login()` and `logout()`, and it remembers the user between requests through the session. - **Stateless** guards implement only `Illuminate\Contracts\Auth\Guard`. They authenticate every request afresh from something the request carries. The framework still contains a basic `token` driver (`TokenGuard`, reading an `api_token` value from the query string, body or bearer header), but the skeleton's comment lists only `session` as supported and the docs send API authentication to **Sanctum** or **Passport**, which register their own `sanctum` and `passport` drivers. A stateless guard has no `login()` method, so "signing in" through it means nothing: each request proves itself again. ## Provider drivers The framework has two provider drivers: - `eloquent` returns instances of the configured model, so the signed-in user has relationships, casts and the `can()` helper. - `database` queries a table through the query builder and returns an `Illuminate\Auth\GenericUser`, a thin object with only the `Authenticatable` methods. An unknown provider driver fails with "Authentication user provider [x] is not defined." ## Common misreadings - Treating "guard" and "provider" as synonyms: the guard never loads user records itself, and the provider never reads cookies or headers. - Assuming one guard per model is mandatory: several guards may share one provider, for example a session guard and a token guard over the same `users` provider. - Editing `AUTH_GUARD` to switch an admin area to another guard: that changes the default for the whole application, not for one set of routes.
- What happens if you call Auth::guard('admin') when config/auth.php has no admin guard?The auth manager looks up `auth.guards.admin`, finds nothing and throws `InvalidArgumentException` with "Auth guard [admin] is not defined." It does not fall back to the default guard. If the guard exists but its `driver` names something neither built in nor registered with `Auth::extend`, the message is "Auth driver [x] for guard [admin] is not defined."
- Can two guards share the same user provider?Yes. A guard only references a provider by name, so a `session` guard for the browser and a token-style guard for an API can both point at `users`. Several guards over one provider is common: the provider only answers where users live, and each guard adds its own way of recognising them.
saying these in an interview costs you the question
- A guard and a user provider are two names for the same thing.
- The web guard stores the whole user object in the session.
- The default users provider queries the users table directly, not through a model.
- Changing AUTH_GUARD is how you protect just the admin routes with another guard.
- An undefined guard name silently falls back to the default guard.