In Laravel's config/auth.php, what changes when a user provider uses the database driver instead of the eloquent driver?
answer
- model key versus table key
- GenericUser instead of your model
- no relationships, casts or can()
- optional connection key
- same UserProvider contract underneath
basics
~20 sAn eloquent provider loads users through a configured model and returns that model; a database provider queries a configured table with the query builder and returns an Illuminate\Auth\GenericUser, which has no relationships, casts, accessors or can() helper.
solid answer
~40 sBoth drivers implement the same `Illuminate\Contracts\Auth\UserProvider` contract, so guards cannot tell them apart. The `eloquent` driver takes a `model` key and returns instances of that model, so `Auth::user()` gives you relationships, casts, accessors, `notify()` and `can()`. The `database` driver takes a `table` key, plus an optional `connection`, queries it with the query builder and wraps the row in `Illuminate\Auth\GenericUser`, which only implements the `Authenticatable` methods and exposes columns as dynamic properties. Password checks and remember-me tokens work in both. Reach for `database` only when no model exists or should exist, such as a legacy table another system owns; in a normal app, `eloquent` is the default for good reason.
go deeper
Know that eloquent uses a model key and returns your model, while database uses a table key and returns a GenericUser.
Explain the shared UserProvider contract, what GenericUser lacks (relationships, casts, can(), notify()), and how credentials are queried before the hash check.
Judge when a database provider is justified, such as a legacy table on another connection, and what features it quietly disables across the app.
Treat the provider as the seam between identity storage and the framework, and decide whether a legacy source deserves a model, a custom provider or a migration.
## Same contract, different return type A **user provider** is any class implementing `Illuminate\Contracts\Auth\UserProvider`. Guards only call its methods: `retrieveById`, `retrieveByToken`, `updateRememberToken`, `retrieveByCredentials`, `validateCredentials` and `rehashPasswordIfRequired`. Laravel ships two implementations, selected by the provider's `driver` key in `config/auth.php`: - `eloquent` builds `Illuminate\Auth\EloquentUserProvider`. - `database` builds `Illuminate\Auth\DatabaseUserProvider`. The Laravel 13 skeleton uses `eloquent` and leaves a commented-out `database` example underneath it. ## Configuration keys | Driver | Required key | Optional key | Returns | |---|---|---|---| | `eloquent` | `model` (a class name) | none | an instance of that model | | `database` | `table` (a table name) | `connection` (a database connection name) | `Illuminate\Auth\GenericUser` | The `eloquent` provider uses whatever connection the model itself uses. The `database` provider uses the default connection unless you set `connection`. ## What `GenericUser` gives you, and what it lacks `GenericUser` wraps the row's columns in an array and implements only the `Authenticatable` methods (`getAuthIdentifier`, `getAuthPassword`, `getRememberToken` and so on), plus magic `__get`/`__set` so `$user->email` works. It is **not** an Eloquent model, so: - there are **no relationships**: `$user->orders` is just a missing column; - there are **no casts or accessors**: dates come back as strings; - there is **no `can()` or `cannot()`**, because those come from the `Authorizable` trait on `Illuminate\Foundation\Auth\User`; gates still run, but you call them through the `Gate` facade; - there is **no `notify()`**, so reset and verification notifications that expect a notifiable model need extra work; - saving changes means writing a query yourself. ## How credentials are looked up Both providers follow the same shape for `retrieveByCredentials`: 1. Drop every credential key containing `password`. 2. Add a `where` for each remaining key (a `whereIn` for arrays, or call a closure for custom conditions). 3. Return the first match, or `null`. The password itself is checked afterwards in `validateCredentials` with the hasher, so neither driver ever puts the plain password in a query. ## When to choose which - **Use `eloquent`** in nearly every application: the rest of Laravel (notifications, policies with type-hinted models, API resources, factories in tests) expects the user to be a model. - **Consider `database`** when authenticating against a table you do not want a model for, for example a read-only table a separate system owns on another connection. - **Write a custom provider with `Auth::provider()`** when users are not in a relational table at all. In a car-dealership back office, staff would normally get an `App\Models\Staff` model and an eloquent provider; a `database` provider would make every controller that touches `$request->user()` lose relationships such as the salesperson's assigned showroom. ## Remember-me tokens and rehashing Both drivers implement the write side of the contract too, just with different tools: - `updateRememberToken` sets the `remember_token` column. The Eloquent provider saves through the model (with timestamps switched off for that save), while the database provider runs a direct `update` on the table, keyed by the identifier column. - `rehashPasswordIfRequired` checks `needsRehash` on the stored hash and, when the hashing configuration has changed, writes a fresh hash of the submitted password. The database provider again does this with a table `update`, so no model events fire. That last point matters when the application relies on model observers or events, for example an audit log that records every change to a user row: with the `database` driver those writes bypass Eloquent entirely. ## Moving from one driver to the other Switching a provider from `database` to `eloquent` is a configuration change plus a model: replace `table` with `model`, make the model extend `Illuminate\Foundation\Auth\User`, and every signed-in user becomes a full model on the next request. Going the other way silently removes relationships and helper methods everywhere `$request->user()` is used, so search the code base for those calls first.
- Can you still authorize a GenericUser with gates?Yes. `Gate::forUser($user)->allows('ability')` or `Gate::allows()` for the current user still work, because gates receive whatever the guard resolved. What is missing is the `can()` convenience method, which comes from the `Authorizable` trait on `Illuminate\Foundation\Auth\User`, not from the provider.
- How do you point a database provider at a table on a second database connection?Add `'connection' => 'legacy'` beside `'table'` in the provider's entry. `DatabaseUserProvider` is built with `$app['db']->connection($config['connection'] ?? null)`, so without the key it uses the default connection.
saying these in an interview costs you the question
- The database provider returns an instance of App\Models\User.
- The database driver skips password hashing and compares plain text.
- GenericUser supports relationships as long as the foreign keys exist.
- Guards need different code depending on which provider driver is used.
- The eloquent provider needs a table key as well as a model key.