Laravel 8 Multi Authentication using Guards

Alagie Singhateh
10 min readJun 23, 2021

--

Click to learn more

Hello guys, in this article we will learn how to create a multi Auth guard with Laravel 8, So let me explain why should you use a multi auth guard in Laravel. Because if you are using an application like school management which has many roles so you wanted each role to see the different dashboard, but you don’t want to add gates or policies, here is we can use guards to prevent each of the users. Click this

For example: if your system is having ( Admin, Staff, and Normal Users ) and you wanted all of them to use the different login forms. this method will help you to achieve that. Click this

STEP 1. CREATE A NEW LARAVEL 8 PROJECT

So here we will create our new Laravel 8 project by using the below command, you can copy the below command and paste it into your terminal to create a new project.

composer create-project --prefer-dist laravel/laravel laravel-8-multi-auth

STEP 2. INSTALLING LARAVEL START-UP KIT

You can use any of the laravel 8 start-up kits, but in this tutorial, I will be using Laravel UI

Run the below command to install Laravel UI

composer require laravel/ui

Run to generate Auth

php artisan ui bootstrap --authnpm installnpm run dev

STEP 3. CREATING A DATABASE AND CONFIGURATION

In this step, we will create a database you can use any type of database providers after creating the database we will need to configure the database credentials inside our .ENV FILE

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE= laravel_multi_auth
DB_USERNAME= root
DB_PASSWORD=

STEP 4. CREATING TWO MODEL ( ADMIN & STAFF )

By default laravel come with a user model, so we will use that as a reference to the two models we are about to create. note: in the user model there is a trait called authenticable so we will use that built-in authenticable feature in this tutorial.

Run the below command to create the two models along with migrations and controllers

php artisan make:model Admin -mrcphp artisan make:model Staff -mrc

STEP 5. SET UP THE TWO MIGRATION FILES

The migration file will be similar to the user migration file so what we will do, we will copy all the fields inside the user migration file and paste it inside each of the two migrations which are Admin and Staff migrations.

So the output will just like the below example code.

USER MIGRATION FILE

<?phpuse Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateUsersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->id('id');
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
$table->softDeletes();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('users');
}
}

ADMIN MIGRATION FILE — note: we will add one new field to the admin model.

<?phpuse Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateAdminsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('admins', function (Blueprint $table) {
$table->id('id');
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->tinyinteger('status')->default(0);
$table->rememberToken();
$table->timestamps();
$table->softDeletes();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('admins');
}
}

STAFF MIGRATION FILE — note: we will add one new field to the staff model.

<?phpuse Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateStaffsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('staffs', function (Blueprint $table) {
$table->id('id');
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->tinyinteger('status')->default(0);
$table->rememberToken();
$table->timestamps();
$table->softDeletes();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('staffs');
}
}

STEP 6. RUNNING MIGRATION

Now I will run the migration command to migrate our table inside the database I created.

Run the below command to migrate the fields.

php artisan migrate

STEP 7. SET UP MODEL SETTINGS

So we need to open the user model as I mentioned above and copy all that is inside the model because the models will be somehow similar to each other, copy the below code snippet, and paste it inside the admin and staff model.

<?phpnamespace App\Models;use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable implements MustVerifyEmail, ShouldQueue
{
use HasFactory, Notifiable, SoftDeletes;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name',
'email',
'password',
'phone',
];
/**
* The attributes that should be hidden for arrays.
*
* @var array
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* The attributes that should be cast to native types.
*
* @var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
}

ADMIN MODEL — Note: inside each model has a trait called Authenticatable

<?phpnamespace App\Models;use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
class Admin extends Authenticatable implements MustVerifyEmail, ShouldQueue
{
use HasFactory, Notifiable, SoftDeletes;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name',
'email',
'password',
'phone',
'status',
];
/**
* The attributes that should be hidden for arrays.
*
* @var array
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* The attributes that should be cast to native types.
*
* @var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
}

STAFF MODEL — Note: inside each model has a trait called Authenticatable

<?phpnamespace App\Models;use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
class Staff extends Authenticatable implements MustVerifyEmail, ShouldQueue
{
use HasFactory, Notifiable, SoftDeletes;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name',
'email',
'password',
'phone',
'status',
];
/**
* The attributes that should be hidden for arrays.
*
* @var array
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* The attributes that should be cast to native types.
*
* @var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
}

STEP 8. SET UP AUTH GUARDS

Inside the config/auth.php we need to add few configurations so that we can able to work with our custom guards. by default in laravel web is a default guard for all the authentication that will be made if there is no other guard defined. so we will define our two custom guards which are the admin guard and staff guard.

Copy and paste the below code to your app.

Config/Auth.php

<?phpreturn [    /*
|--------------------------------------------------------------------------
| Authentication Defaults
|--------------------------------------------------------------------------
|
| This option controls the default authentication "guard" and password
| reset options for your application. You may change these defaults
| as required, but they're a perfect start for most applications.
|
*/
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
/*
|--------------------------------------------------------------------------
| Authentication Guards
|--------------------------------------------------------------------------
|
| Next, you may define every authentication guard for your application.
| Of course, a great default configuration has been defined for you
| here which uses session storage and the Eloquent user provider.
|
| All authentication drivers have a user provider. This defines how the
| users are actually retrieved out of your database or other storage
| mechanisms used by this application to persist your user's data.
|
| Supported: "session", "token"
|
*/
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
'hash' => false,
],
'admin' => [
'driver' => 'session',
'provider' => 'admins',
],
'admin-api' => [
'driver' => 'token',
'provider' => 'admins',
'hash' => false,
],
'staff' => [
'driver' => 'session',
'provider' => 'staffs',
],
'staff-api' => [
'driver' => 'token',
'provider' => 'staffs',
'hash' => false,
],
],
/*
|--------------------------------------------------------------------------
| User Providers
|--------------------------------------------------------------------------
|
| All authentication drivers have a user provider. This defines how the
| users are actually retrieved out of your database or other storage
| mechanisms used by this application to persist your user's data.
|
| If you have multiple user tables or models you may configure multiple
| sources which represent each model / table. These sources may then
| be assigned to any extra authentication guards you have defined.
|
| Supported: "database", "eloquent"
|
*/
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
'admins' => [
'driver' => 'eloquent',
'model' => App\Admin::class,
],
'staffs' => [
'driver' => 'eloquent',
'model' => App\Staff::class,
],
// 'users' => [
// 'driver' => 'database',
// 'table' => 'users',
// ],
],
/*
|--------------------------------------------------------------------------
| Resetting Passwords
|--------------------------------------------------------------------------
|
| You may specify multiple password reset configurations if you have more
| than one user table or model in the application and you want to have
| separate password reset settings based on the specific user types.
|
| The expire time is the number of minutes that the reset token should be
| considered valid. This security feature keeps tokens short-lived so
| they have less time to be guessed. You may change this as needed.
|
*/
'passwords' => [
'users' => [
'provider' => 'users',
'table' => 'password_resets',
'expire' => 60,
'throttle' => 60,
],
'admins' => [
'provider' => 'admins',
'table' => 'password_resets',
'expire' => 60,
'throttle' => 60,
],
'staffs' => [
'provider' => 'staffs',
'table' => 'password_resets',
'expire' => 60,
'throttle' => 60,
],
],
/*
|--------------------------------------------------------------------------
| Password Confirmation Timeout
|--------------------------------------------------------------------------
|
| Here you may define the amount of seconds before a password confirmation
| times out and the user is prompted to re-enter their password via the
| confirmation screen. By default, the timeout lasts for three hours.
|
*/
'password_timeout' => 10800,];

STEP 9. SET UP ROUTESERVICE PROVIDER

Inside the route service provider under the boot method, we will see all the registered routes from Web to APIS, but we need to add two custom configurations to the existing routes which will be the admin and the staff route. by default, there are two routes that are already defined (API and Web ) for the default users. So we will add admin and staff routes below the user routes.

Copy the below code and paste it inside the route service provide, located under app/Providers/RouteServiceProvider

<?phpnamespace App\Providers;use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\Facades\Route;
class RouteServiceProvider extends ServiceProvider
{
/**
* The path to the "home" route for your application.
*
* This is used by Laravel authentication to redirect users after login.
*
* @var string
*/
public const HOME = '/dashboard';
/**
* The controller namespace for the application.
*
* When present, controller route declarations will automatically be prefixed with this namespace.
*
* @var string|null
*/
// protected $namespace = 'App\\Http\\Controllers';
/**
* Define your route model bindings, pattern filters, etc.
*
* @return void
*/
public function boot()
{
$this->configureRateLimiting();
$this->routes(function () { // En-User
Route::prefix('api')
->middleware('api')
->namespace($this->namespace)
->group(base_path('routes/api.php'));
Route::middleware('web')->name('users.')
->namespace($this->namespace)
->group(base_path('routes/web.php'));
// Admin User
Route::prefix('admin')->name('admin.')
->middleware('web')
->namespace($this->namespace)
->group(base_path('routes/admin.php'));
// Staff User
Route::prefix('staff')->name('staff.')
->middleware('web')
->namespace($this->namespace)
->group(base_path('routes/staff.php'));
});
}
/**
* Configure the rate limiters for the application.
*
* @return void
*/
protected function configureRateLimiting()
{
RateLimiter::for('api', function (Request $request) {
return Limit::perMinute(60)->by(optional($request->user())->id ?: $request->ip());
});
}
}

STEP 10. CREATE CUSTOM ROUTE FILES

In this part, we will need to create 2 new files under the routes folder. structure as follows below:

  • admin.php
  • staff.php

Under Routes/Admin.php — copy and paste the below code inside.

<?phpuse Illuminate\Support\Facades\Route;
use App\Http\Controllers\Auth\Admin\AdminController;
// IF THE ADMIN USER DON NOT LOGIN CAN ABLE TO SEE THIS ROUTES
Route::middleware(['guest:admin'])->group(function () {
Route::post('register', [AdminController::class, 'AdminRegisteration'])->name('register');
Route::get('/', [AdminController::class, 'AdminLoginForm'])->name('login.form');
Route::post('postlogin', [AdminController::class, 'AdminLogin'])->name('login');
});
// IF THE ADMIN USER LOGGEDIN CAN ABLE TO SEE THIS ROUTES
Route::middleware(['auth:admin'])->group(function () {
Route::get('dashboard', [AdminController::class, 'Dashboard'])->name('dashboard');
Route::post('logout', [AdminController::class, 'AdminLogout'])->name('logout');
});

Under Routes/Staff.php — copy and paste the below code inside.

<?phpuse Illuminate\Support\Facades\Route;
use App\Http\Controllers\StaffController;
Route::middleware(['guest:staff'])->group(function () {
Route::get('/auth', [StaffController::class, 'StaffLoginForm'])->name('login.form');
Route::post('postlogin', [StaffController::class, 'StaffLogin'])->name('login');
});
Route::middleware(['auth:staff'])->group(function () {
Route::get('dashboard', [StaffController::class, 'Dashboard'])->name('dashboard');
Route::post('logout', [StaffController::class, 'StaffLogout'])->name('logout');
});

STEP 11. SET UP AUTHENTICATE MIDDLEWARE

In this part, we need to configure our authenticate middleware under Http/Middleware/Authenticate.php

so that when the user or admin or staff login fails the guard will redirect them back to their login page, so let’s copy and paste the below code inside.

Http/Middleware/Authenticate.php

<?phpnamespace App\Http\Middleware;use Illuminate\Auth\Middleware\Authenticate as Middleware;class Authenticate extends Middleware
{
/**
* Get the path the user should be redirected to when they are not authenticated.
*
* @param \Illuminate\Http\Request $request
* @return string|null
*/
protected function redirectTo($request)
{
if (! $request->expectsJson()) {
if ($request->routeIs('admin.*')) {
return route('admin.login.form');
}elseif ($request->routeIs('staff.*')) {
return route('staff.login.form');
}
return route('users.login.form');
}
}
}

STEP 12. SET UP REDIRECTIFAUTHENTICATED MIDDLEWARE

In this part, we need to configure our RedirectIfAuthenticated middleware under Http/Middleware/RedirectIfAuthenticated.php

So that when the user or admin or staff logged in successfully the guard will redirect them to their dashboard, so let’s copy and paste the below code inside.

Http/Middleware/RedirectIfAuthenticated.php

<?phpnamespace App\Http\Middleware;use App\Providers\RouteServiceProvider;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class RedirectIfAuthenticated
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param string|null ...$guards
* @return mixed
*/
public function handle(Request $request, Closure $next, ...$guards)
{
$guards = empty($guards) ? [null] : $guards;
foreach ($guards as $guard) {
if (Auth::guard($guard)->check()) {
if ($guard === 'admin') {
return redirect(route('admin.dashboard'));
}elseif ($guard === 'staff') {
return redirect(route('staff.dashboard'));
}
return redirect(RouteServiceProvider::HOME);
}
}
return $next($request);
}
}

STEP 13. SET UP CONTROLLERS

In this part, we will work with the controllers to implement our logic on how both the user and admin will able to login to their dashboard from different login forms.

Let’s start with the AdminController

app/Http/Controllers/AdminController.php

<?phpnamespace App\Http\Controllers;use Illuminate\Http\Request;
use Vonage\Message\Shortcode\Alert;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;
use Illuminate\Validation\ValidationException;
class AdminController extends Controller
{
public function AdminLoginForm()
{
return view('auth.admin.login');
}
public function AdminLogin(Request $request)
{
$credential = $request->only(['email', 'password']);
if (Auth::guard('admin')->attempt($credential, $request->filled('remember'))) { return redirect()->route('admin.dashboard');
} else {
throw ValidationException::withMessages([
'email' => 'invalid email or password'
]);
}
}
public function AdminLogout()
{
Auth::guard('admin')->logout();
return redirect(route('admin.login.form'));
}
}

app/Http/Controllers/StaffController.php

<?phpnamespace App\Http\Controllers;use Illuminate\Http\Request;
use Vonage\Message\Shortcode\Alert;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;
use Illuminate\Validation\ValidationException;
class AdminController extends Controller
{
public function StaffLoginForm()
{
return view('auth.staff.login');
}
public function StaffLogin(Request $request)
{
$credential = $request->only(['email', 'password']);
if (Auth::guard('staff')->attempt($credential, $request->filled('remember'))) { return redirect()->route('staff.dashboard');
} else {
throw ValidationException::withMessages([
'email' => 'invalid email or password'
]);
}
}
public function StaffLogout()
{
Auth::guard('staff')->logout();
return redirect(route('staff.login.form'));
}
}

CONCLUSION

There is how to make a multi auth guard using a built-in laravel guard with any package hopefully when you read this article will help you to understand how to set up your custom guards in laravel with multi-auth-users in one application.

Thank you, if this article is helpful to you please do not forget to share and comment below or if you get confuse kindly leave a comment we will get back to you with a help.

--

--