Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Multi Auth Laravel Package

bmatovu/multi-auth

Laravel MultiAuth simplifies authenticating multiple user types—such as admins and customers—with separate guards, providers, and tables. Configure guards, protect routes with middleware, and manage independent logins for each user model without conflicts.

View on GitHub
Deep Wiki
Context7

Getting Started

bmatovu/multi-auth is a scaffolding package for running several independent Laravel auth guards (e.g. web for customers, admin for staff, vendor for partners) without hand-wiring every controller, route, view, and provider. Treat it as a generator you run once per guard, not a runtime library you call into constantly.

Minimal path from zero to working second guard:

  1. Install and publish:
    composer require bmatovu/multi-auth
    php artisan vendor:publish --tag=multi-auth
    
  2. Read config/multi-auth.php first — it is the source of truth for the guard name, model namespace, route prefix, redirect targets, and view namespace the generator will emit.
  3. Generate a guard:
    php artisan multi-auth:make admin
    
    This typically scaffolds the Eloquent model, migration, guard/provider entries in config/auth.php, login/register controllers, routes, and Blade views.
  4. Run php artisan migrate and confirm config/auth.php now has a matching guards.admin and providers.admins pair pointing at the generated model.
  5. Register the guard's middleware in app/Http/Kernel.php (or bootstrap/app.php on Laravel 11+, which is officially supported as of v12.1.0) so auth:admin and guest:admin resolve.

Version note: v12.1.0 adds first-class Laravel 11 support. If you are on Laravel 11 and previously had to hand-patch around middleware registration, that workaround can now be dropped — pin "bmatovu/multi-auth": "^12.1" and use the bootstrap/app.php middleware registration natively.

First real use case: split an existing single-guard app so /admin requires an Admin model while the public site keeps using User. Start by generating admin, then move only the admin routes into a group with middleware(['web', 'auth:admin']) — do not migrate the public guard at the same time, or you will spend the afternoon debugging session collisions.

Where to look when something is off, in order: the published config, the generated config/auth.php block, the generated controllers under app/Http/Controllers/Auth, then the package's own src/ commands if the output does not match your expectations.

Implementation Patterns

One guard per actor type, one provider per model. Keep the naming symmetric (admin guard → admins provider → App\Models\Admin) and let the generator handle the boilerplate. Asymmetry here is the most common source of "wrong user logged in" bugs.

Route grouping by guard. Isolate each surface with its own middleware stack:

Route::middleware(['web', 'auth:admin'])->prefix('admin')->group(function () {
    Route::get('/dashboard', [AdminDashboardController::class, 'index']);
});

Use guest:admin on the login/register routes so an authenticated admin is never shown the login form.

Laravel 11+ middleware registration. With v12.1.0 the guard middleware can be registered the Laravel 11 way in bootstrap/app.php instead of editing Kernel.php:

->withMiddleware(function (Middleware $middleware) {
    // No package-specific registration needed for the built-in
    // auth / guest middleware aliases; just reference auth:admin
    // and guest:admin directly in route groups.
})

If you were previously patching the package for Laravel 11, remove that patch — reinstall ^12.1 cleanly.

Explicit guard resolution everywhere. Never rely on the default guard when multiple exist. In controllers, policies, and Blade:

Auth::guard('admin')->user();
Auth::guard('admin')->check();
Auth::guard('admin')->logout();

In Blade, prefer @auth('admin') ... @endauth over @auth, which silently falls back to the default guard.

Redirect targets belong in config, not controllers. Point the generated LoginController's $redirectTo at a config value (or route('admin.dashboard')) so staging and production can diverge. Same for RedirectIfAuthenticated — the package's default redirect will send everyone to /home, which is usually wrong for a secondary guard.

Cross-guard access is a deliberate pattern, not the default. When an admin needs to act on a customer record, load the customer via its own model (User::find($id)) rather than trying Auth::guard('web'). The logged-in admin has no relationship to the customer's session.

Middleware composition for shared areas. For pages both a customer and a vendor can see, either stack auth:web,vendor (Laravel accepts multiple guards and passes if any matches) or write a thin EnsureAnyGuard middleware that records which guard succeeded and exposes it to the view.

Testing pattern. Always pin the guard in tests:

$this->actingAs($admin, 'admin')->get('/admin/dashboard')->assertOk();
$this->get('/admin/dashboard')->assertRedirect('/admin/login');

The second assertion catches the classic failure where auth:admin is missing from the route group but the test still passes because the default web guard is authenticated.

Password resets per guard. Each guard needs its own password broker entry in config/auth.php (passwords.admins with its own table and expiry). The generator emits this; verify it, because a missing broker means Password::broker('admins') silently fails at runtime.

Gotchas and Tips

  • Session guard collisions. Two session guards sharing the same cookie name will clobber each other's session. The package does not rename cookies for you — set distinct 'cookie' values on each session guard in config/auth.php if you see users bouncing between logins.
  • auth:admin throws before the controller runs. A Route [login] not defined error on an unauthenticated hit usually means the guard's redirectTo points at a named route the generator did not create, or the route is defined with a different name (admin.login vs login). Grep for the name in config/auth.php and the generated controllers.
  • Config caching hides generated changes. php artisan multi-auth:make writes to config/auth.php at disk level. If config:cache was run beforehand, your new guard is invisible until php artisan config:clear. Make this the first step of any "it worked yesterday" debugging.
  • Model must implement Authenticatable. Generated models do, but if you reuse an existing model (e.g. Admin that already extends something else), you must implements Authenticatable and pull in AuthenticatableTrait, plus a getAuthIdentifierName that matches the provider's model key.
  • Eloquent provider lookup by email is global across the table. If two guards ever point at the same table (happens when copying config blocks), credentials leak between actor types. Audit config/auth.php after each generation for duplicated model entries.
  • Migrations are timestamped at generation time. Generating two guards in the same minute can produce identical migration timestamps and out-of-order execution. Rename one before migrate, especially in CI where ordering is deterministic.
  • View namespace is your override point. Publish the views (vendor:publish --tag=multi-auth-views) and edit the published copies rather than the vendor tree — package updates will overwrite vendor files. Same for controllers: extend the generated controller in app/Http/Controllers rather than editing package classes.
  • Events and listeners are not per-guard by default. Illuminate\Auth\Events\Login fires for every guard. Use $event->guard inside listeners to branch, or you will trigger admin-only side effects on customer logins.
  • Laravel 11 upgrade path (v12.1.0). If you were previously stuck on ^3.0 because you needed Laravel 11 support, upgrade to ^12.1 and re-run generation for any guards where you hand-patched middleware registration. The generated bootstrap/app.php wiring is now native. Re-check published views/controllers — a major version hop may have changed the generated output.
  • Small community, sparse issues. With roughly 180 stars and no dependents, expect to read the generator source when behavior diverges from the README. Pin the version in composer.json ("bmatovu/multi-auth": "^12.1" for the current Laravel 11-compatible line) and budget a half-day for the first upgrade to skim what the generator now emits differently.
  • Extension point to prefer. When you need something the generator does not produce (SSO, magic links, API tokens per guard), implement it in a normal Laravel controller and register the route yourself — do not patch the package. Keep the generated files as a starting point and let your app own the divergence.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect
youbar/easy-crud
c-point-labs/laravel-hostyourai
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo