Updated 23 July 2026
Have you ever wondered how Bagisto allows an administrator to manage the store from the admin panel while customers shop on the storefront—without their sessions interfering with each other?
The answer is Laravel’s Multi-Guard Authentication. It allows different types of users to authenticate independently within the same application.
In this article, you’ll learn what a guard is, how Bagisto implements multi-guard authentication, why admin and customer sessions never conflict, how to extend it with your own custom guards, and the best practices to follow when building your own Bagisto modules.

A guard in Laravel determines how a user is authenticated for every request. It tells Laravel which authentication method to use and where to retrieve the authenticated user.
Laravel supports multiple authentication guards, allowing an application to manage different types of users independently.
For example, a web application may have:
| Guard | Purpose |
|---|---|
customer |
Authenticates storefront customers |
admin |
Authenticates administrators |
Each guard has its own authentication flow, making it possible for multiple user types to coexist securely in the same application.
Multi-Guard Authentication means using multiple guards within a single Laravel application.
Instead of authenticating every user from the same table and session, each guard has its own:
Bagisto uses this approach to completely separate customers from administrators while running both interfaces within the same Laravel application.
Bagisto defines two session-based guards inside config/auth.php.
|
1 2 3 4 5 6 7 8 9 10 11 |
'guards' => [ 'customer' => [ 'driver' => 'session', 'provider' => 'customers', ], 'admin' => [ 'driver' => 'session', 'provider' => 'admins', ], ]; |
Each guard is linked to its own provider, allowing Bagisto to authenticate administrators and customers independently.
| Guard | Model | Database Table |
|---|---|---|
customer |
Customer | customers |
admin |
Admin | admins |
Two guards, two providers, two models, two tables, two reset flows. Complete isolation by design.
This separation ensures both user types remain completely isolated.
Although both guards use Laravel’s session driver, Laravel stores each authenticated user under a unique session key derived from the guard name.
|
1 2 |
login_customer_<hash> => 42 // a logged-in customer login_admin_<hash> => 7 // a logged-in admin |
Because the session keys are different strings, they live side by side in the same session payload:
login_admin_* — the customer session survives untouched.auth()->guard('admin')->check() inspects only the admin key; it knows nothing about the customer key.This is the mechanical answer to “how do two panels coexist without conflict”: different guards write to different session keys.
Notice how each side authenticates against its own guard explicitly. Here’s what a simplified admin login attempt looks like:
|
1 2 3 4 5 6 7 8 9 10 11 |
// Admin SessionController — always names the 'admin' guard if (! auth()->guard('admin')->attempt($credentials)) { return redirect()->back()->withErrors([ 'email' => trans('admin::app.errors.invalid-credentials'), ]); } // After success, admins are additionally checked for ACL permission if (! bouncer()->hasPermission('dashboard')) { auth()->guard('admin')->logout(); } |
And the customer side does the mirror image:
|
1 2 3 4 5 6 |
// Shop SessionController — always names the 'customer' guard if (! auth()->guard('customer')->attempt($credentials)) { return redirect()->back()->withErrors([ 'email' => trans('shop::app.errors.invalid-credentials'), ]); } |
Guards decide how to authenticate; middleware decides which routes require it. Bagisto registers two aliases inside its service providers (not the global HTTP kernel):
Then each package wraps its protected routes in the matching middleware:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// Admin routes — guarded by the 'admin' middleware (Bouncer) Route::group([ 'middleware' => ['admin', NoCacheMiddleware::class], 'prefix' => config('app.admin_url'), ], function () { // dashboard, catalog, orders, settings... }); // Storefront account routes — guarded by the 'customer' middleware Route::group([ 'middleware' => ['customer', NoCacheMiddleware::class], ], function () { // profile, addresses, wishlist, logout... }); |
This ensures customers cannot access admin routes, while administrators don’t automatically become authenticated customers on the storefront.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
Customer Login │ ▼ Customer Guard │ ▼ Customer Provider │ ▼ Customers Table │ ▼ login_customer_* │ ▼ Customer Dashboard |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
Admin Login │ ▼ Admin Guard │ ▼ Admin Provider │ ▼ Admins Table │ ▼ login_admin_* │ ▼ Admin Dashboard |
Even though both users share the same browser session, Laravel keeps their authentication completely separate.
Because this is just Laravel, you can extend it. Suppose your module needs a third audience — say authors who are neither shop admins nor customers. You’d add a new guard named after that audience (call it author, or anything that fits your use case) as a full stack in config/auth.php:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
'guards' => [ // ...existing customer and admin guards... 'author' => [ 'driver' => 'session', 'provider' => 'authors', ], ], 'providers' => [ // ... 'authors' => [ 'driver' => 'eloquent', 'model' => Webkul\Author\Models\Author::class, ], ], |
Then use it exactly like the others:
|
1 2 3 |
if (auth()->guard('author')->attempt($credentials)) { return redirect()->route('author.dashboard'); } |
Laravel gives this new guard its own login_author_* session key automatically — so it coexists with customers and admins, conflict-free, following the identical pattern. Whatever audience you need, just name a new guard for it and follow the same structure.
When developing Bagisto modules:
auth()->guard('admin') or auth()->guard('customer'). Relying on the default guard inside a package is a subtle bug waiting to happen when that code runs on the “wrong” side.admin or customer middleware so authorization is declarative and consistent.Avoid these common mistakes when working with multiple guards:
auth()->user() in admin code returns the customer (the default guard) or null — leading to confusing “I’m logged in but the app says I’m not” bugs.auth()->guard('admin')->logout() signs out only the admin. If you intend to end all sessions, you must log out each guard (or invalidate the session entirely).Bagisto leverages Laravel’s Multi-Guard Authentication to provide secure, independent authentication for administrators and customers within the same application.
By separating guards, providers, models, and session keys, Bagisto ensures both user types can work simultaneously without interfering with each other’s sessions. Middleware like AuthenticateCustomer and Bouncer then decide which routes each identity may enter, with the admin side adding ACL permission checks on top.
Understanding this architecture not only helps you troubleshoot authentication issues but also enables you to build secure and scalable Bagisto modules that follow Laravel’s best practices.
You can also hire laravel developers to build custom solutions on Laravel. To explore ready-made add-ons, visit the Bagisto extension marketplace.
If you have more details or questions, you can reply to the received confirmation email.
Back to Home
Be the first to comment.