LaravelTutorials

Laravel 7 Multi Authentication Tutorial

If you have used Laravel for a while, you should have heard a lot about multiple authentications. You should have also heard “guards” a whole lot. But if you are fairly new to Laravel, multiple authentications makes it possible for you to have different classes of users access different/similar parts of the same application.

There are many reasons why you may want to use multiple authentications in your Laravel application. For example, you have a large application that runs an entire company. Customers also interact with the product and services of the company through the same application. The application also has a blog and there is a department in the company responsible for handling the blog.

We can see from the application above that there are already three sets of users. For customers, we can have them use a certain authentication process to access the system. For writers, they could have a totally different authentication process and even have roles to enable a more robust content management process. For the rest of the company, you can have different roles representing different functions.

Now, let us look at how to create multiple authentications for our different class of users. In this tutorial, we will create laravel 7 multiple authentication using guard.

Prerequisites

  1. Knowledge of PHP .
  2. Knowledge of Laravel .
  3. Composer is installed on your computer.
  4. Laravel installer is installed on your computer.

Getting started

If you checked off all the items on the prerequisites list, then this tutorial is already looking solid for you. We will create a Laravel app that has three user classes — admin, vendor, user. We will make guards for the three user classes and restrict different parts of our application based on those guards.

Step 1: Create the application

We need to create a new Laravel application. Run the following command on your terminal to create a new Laravel application:

$ laravel new multi-auth
or
$ composer create-project --prefer-dist laravel/laravel multi-auth
$ cd multi-auth

Step 2: Database Configuration

In the second step, we will make database configuration. Open the .env file in your application directory and change the following section:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=here your database name(blog)
DB_USERNAME=here database username(root)
DB_PASSWORD=here database password(root)

Creating Models & Migrations

We will make models & migrations for the admins and vendors tables as Laravel comes with a users migration. They will be as simple as the users table, but you can extend them further based on your specific needs.

Step 3: Create Models & Migrations for admins & vendors

To make the admins & vendors model as well as table, run the following commands:

$ php artisan make:model Admin -m
$ php artisan make:model Vendor -m

Step 4: Update the models

Go to the Admin & Vendor model in the app directory of your application folder and write as below:

app/Admin.php

    // app/Admin.php
    <?php

    namespace App;

    use Illuminate\Notifications\Notifiable;
    use Illuminate\Foundation\Auth\User as Authenticatable;

    class Admin extends Authenticatable
    {
        use Notifiable;

        protected $guard = 'admin';

        protected $fillable = [
            'name', 'email', 'password',
        ];

        protected $hidden = [
            'password', 'remember_token',
        ];
    }

app/Vendor.php

    // app/Vendor.php
    <?php

    namespace App;

    use Illuminate\Notifications\Notifiable;
    use Illuminate\Foundation\Auth\User as Authenticatable;

    class Vendor extends Authenticatable
    {
        use Notifiable;

        protected $guard = 'vendor';

        protected $fillable = [
            'name', 'email', 'password',
        ];

        protected $hidden = [
            'password', 'remember_token',
        ];
    }

Step 5: Update the migration tables

Go to the Admin & Vendor migration table in thedatabase->migrationsdirectory of your application folder and write as below:

admin migration table

    // database/migrations/<timestamp>_create_admins_table.php

    [...]
    public function up()
    {
        Schema::create('admins', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->string('email')->unique();
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
        });
    }
    [...]

vendor migration table

    // database/migrations/<timestamp>_create_vendors_table.php
    
    [...]
    public function up()
    {
        Schema::create('vendors', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->string('email')->unique();
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
        });
    }
    [...]

Step 6: Migrate the database

Now that we have defined our tables, let us migrate the database:

$ php artisan migrate

Step 7: Create Auth using scaffold

Now, in this step, we will create auth scaffold command to create login, register and dashboard. so run following commands:

Laravel 7 UI Package

$ composer require laravel/ui 

Generate auth

$ php artisan ui vue --auth 
$ npm install
$ npm run dev

Step 8: Define the guards

Laravel guards define how users are authenticated for each request. Laravel comes with some guards for authentication, but we can also create ours as well. This will enable us to use Laravel’s default authentication system with our Admin and Vendor models as well.

Open config/auth.php and add the new guards edit as follows:

    // config/auth.php

    <?php

    [...]
    'guards' => [
        [...]
        'admin' => [
            'driver' => 'session',
            'provider' => 'admins',
        ],
        'vendor' => [
            'driver' => 'session',
            'provider' => 'writers',
        ],
    ],
    [...]

Step 9: Set providers for guards

We added two new guards admin and vendor and set their providers. These providers tell Laravel what to use for authentication or validation when we try to use the guard.

Now, add the following to the providers array again in the same file:

    // config/auth.php

    [...]
    'providers' => [
        [...]
        'admins' => [
            'driver' => 'eloquent',
            'model' => App\Admin::class,
        ],
        'vendors' => [
            'driver' => 'eloquent',
            'model' => App\Writer::class,
        ],
    ],
    [...]

Now, we have set up the providers we defined along with the guards above. We set the driver to be eloquent since we are using Eloquent ORM as our database manager.

Let’s say we wish to use another ORM like RedBeanPHP for managing our database, we can then set the driver to say redbeanphp instead of eloquent. For the model, we pass the model we want that provider to use.

We can add password reset functionality for both of our models too as our User model has. To do that change the following

// config/auth.php

   'passwords' => [
        'users' => [
            'provider' => 'users',
            'table' => 'password_resets',
            'expire' => 60,
            'throttle' => 60,
        ],
        'admins' => [
            'provider' => 'admins',
            'table' => 'password_resets',
            'expire' => 60,
            'throttle' => 60,
        ],
        'vendors' => [
            'provider' => 'vendors',
            'table' => 'password_resets',
            'expire' => 60,
            'throttle' => 60,
        ],
    ],

Set up the controllers

To use our guards for authentication, we can either modify the existing authentication controllers or create new ones. You can choose which to use based on your specific needs. In this tutorial, we will create new separate controllers for clean definition.

Step 10: Admin & Vendor controller for login, register & dashboard

Make the following command in your terminal to create new Admin as well as Vendor login & register controller inside the same app->Http->Controllers->Auth directory where Laravel by default creates for our User model controller.

// Admin login
$ php artisan make:controller Auth/AdminLoginController

// Admin register
$ php artisan make:controller Auth/AdminRegisterController

// Admin dashboard
$ php artisan make:controller Users/Admin/AdminController

// Vendor login
$ php artisan make:controller Auth/VendorLoginController

// Vendor register
$ php artisan make:controller Auth/VendorRegisterController

// Vendor dashboard
$ php artisan make:controller Users/Vendor/VendorController

Step 11: Modify Admin & Vendor controllers

So far we have created four separate controllers. Now we need to modify each controller to show login & register form as well as dashboard for both Admin & Vendor model. Lets do the following:

Admin login controller
app->Http->Controllers->Auth->AdminLoginController.php

<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class AdminLoginController extends Controller
{
    public function __construct()
    {
        $this->middleware('guest:admin')->except('logout');
    }

    public function showLoginForm()
    {
        return view('auth.admin-login');
    }

    public function login(Request $request)
    {
        // Validate form data
        $this->validate($request, [
            'email' => 'required|email',
            'password' => 'required|min:8'
        ]);

        // Attempt to log the user in
        if(Auth::guard('admin')->attempt(['email' => $request->email, 'password' => $request->password], $request->remember))
        {
            return redirect()->intended(route('admin.dashboard'));
        }

        // if unsuccessful
        return redirect()->back()->withInput($request->only('email','remember'));
    }
}

Admin register controller
app->Http->Controllers->Auth->AdminRegisterController.php

<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\Admin;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;

class AdminRegisterController extends Controller
{
    public function __construct()
    {
        $this->middleware('guest:admin');
    }

    public function showRegisterForm()
    {
        return view('auth.admin-register');
    }

    public function register(Request $request)
    {
        $this->validate($request, [
            'name' => ['required', 'string', 'max:255'],
            'email' => ['required', 'string', 'email', 'max:255', 'unique:admins'],
            'password' => ['required', 'string', 'min:8', 'confirmed'],
        ]);

        $request['password'] = Hash::make($request->password);
        Admin::create($request->all());

        return redirect()->intended(route('admin.dashboard'));
    }
}

Admin controller
app->Http->Controllers->Users->Admin->AdminController.php

<?php

namespace App\Http\Controllers\Users\Admin;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;

class AdminController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth:admin');
    }

    public function index()
    {
        return view('admin');
    }
}

Vendor login controller
app->Http->Controllers->Auth->VendorLoginController.php

<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class VendorLoginController extends Controller
{
    public function __construct()
    {
        $this->middleware('guest:vendor')->except('logout');
    }

    public function showLoginForm()
    {
        return view('auth.vendor-login');
    }

    public function login(Request $request)
    {
        // Validate form data
        $this->validate($request, [
            'email' => 'required|email',
            'password' => 'required|min:8'
        ]);

        // Attempt to log the user in
        if(Auth::guard('vendor')->attempt(['email' => $request->email, 'password' => $request->password], $request->remember))
        {
            return redirect()->intended(route('vendor.dashboard'));
        }

        // if unsuccessful
        return redirect()->back()->withInput($request->only('email','remember'));
    }
}

Vendor register controller
app->Http->Controllers->Auth->VendorRegisterController.php

<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\Vendor;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;

class VendorRegisterController extends Controller
{
    public function __construct()
    {
        $this->middleware('guest:vendor');
    }

    public function showRegisterForm()
    {
        return view('auth.vendor-register');
    }

    public function register(Request $request)
    {
        $this->validate($request, [
            'name' => ['required', 'string', 'max:255'],
            'email' => ['required', 'string', 'email', 'max:255', 'unique:vendors'],
            'password' => ['required', 'string', 'min:8', 'confirmed'],
        ]);

        $request['password'] = Hash::make($request->password);
        Vendor::create($request->all());

        return redirect()->intended(route('vendor.dashboard'));
    }
}

Vendor controller
app->Http->Controllers->Users->Vendor->VendorController.php

<?php

namespace App\Http\Controllers\Users\Vendor;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;

class VendorController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth:vendor');
    }

    public function index()
    {
        return view('vendor');
    }
}

Step 12: Set up the Authentication pages for Admin & Vendor

In the step: 7 we have already generated Laravel’s auth scaffolding. We can use those generated pages for our authentication system. But as we have created separate controllers again we will create separate pages for our models. Follow the below:

First create a pages inside views->auth directory and correspondingly rename those pages a below:

$ touch resources/views/auth/admin-login.blade.php
$ touch resources/views/auth/admin-register.blade.php
$ touch resources/views/auth/vendor-login.blade.php
$ touch resources/views/auth/vendor-register.blade.php

Modify the pages as below:

admin-login.blade.php

@extends('layouts.app')

@section('content')
    <div class="container">
        <div class="row justify-content-center">
            <div class="col-md-8">
                <div class="card">
                    <div class="card-header">{{ __('Admin Login') }}</div>

                    <div class="card-body">
                        <form method="POST" action="{{ route('admin.login.submit') }}">
                            @csrf

                            <div class="form-group row">
                                <label for="email" class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label>

                                <div class="col-md-6">
                                    <input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ old('email') }}" required autocomplete="email" autofocus>

                                    @error('email')
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $message }}</strong>
                                    </span>
                                    @enderror
                                </div>
                            </div>

                            <div class="form-group row">
                                <label for="password" class="col-md-4 col-form-label text-md-right">{{ __('Password') }}</label>

                                <div class="col-md-6">
                                    <input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" required autocomplete="current-password">

                                    @error('password')
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $message }}</strong>
                                    </span>
                                    @enderror
                                </div>
                            </div>

                            <div class="form-group row">
                                <div class="col-md-6 offset-md-4">
                                    <div class="form-check">
                                        <input class="form-check-input" type="checkbox" name="remember" id="remember" {{ old('remember') ? 'checked' : '' }}>

                                        <label class="form-check-label" for="remember">
                                            {{ __('Remember Me') }}
                                        </label>
                                    </div>
                                </div>
                            </div>

                            <div class="form-group row mb-0">
                                <div class="col-md-8 offset-md-4">
                                    <button type="submit" class="btn btn-primary">
                                        {{ __('Login') }}
                                    </button>

                                    @if (Route::has('password.request'))
                                        <a class="btn btn-link" href="{{ route('password.request') }}">
                                            {{ __('Forgot Your Password?') }}
                                        </a>
                                    @endif
                                </div>
                            </div>
                        </form>
                    </div>
                </div>
            </div>
        </div>
    </div>
@endsection

admin-register.blade.php

@extends('layouts.app')

@section('content')
    <div class="container">
        <div class="row justify-content-center">
            <div class="col-md-8">
                <div class="card">
                    <div class="card-header">{{ __('Admin Register') }}</div>

                    <div class="card-body">
                        <form method="POST" action="{{ route('admin.register.submit') }}">
                            @csrf

                            <div class="form-group row">
                                <label for="name" class="col-md-4 col-form-label text-md-right">{{ __('Name') }}</label>

                                <div class="col-md-6">
                                    <input id="name" type="text" class="form-control @error('name') is-invalid @enderror" name="name" value="{{ old('name') }}" required autocomplete="name" autofocus>

                                    @error('name')
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $message }}</strong>
                                    </span>
                                    @enderror
                                </div>
                            </div>

                            <div class="form-group row">
                                <label for="email" class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label>

                                <div class="col-md-6">
                                    <input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ old('email') }}" required autocomplete="email">

                                    @error('email')
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $message }}</strong>
                                    </span>
                                    @enderror
                                </div>
                            </div>

                            <div class="form-group row">
                                <label for="password" class="col-md-4 col-form-label text-md-right">{{ __('Password') }}</label>

                                <div class="col-md-6">
                                    <input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" required autocomplete="new-password">

                                    @error('password')
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $message }}</strong>
                                    </span>
                                    @enderror
                                </div>
                            </div>

                            <div class="form-group row">
                                <label for="password-confirm" class="col-md-4 col-form-label text-md-right">{{ __('Confirm Password') }}</label>

                                <div class="col-md-6">
                                    <input id="password-confirm" type="password" class="form-control" name="password_confirmation" required autocomplete="new-password">
                                </div>
                            </div>

                            <div class="form-group row mb-0">
                                <div class="col-md-6 offset-md-4">
                                    <button type="submit" class="btn btn-primary">
                                        {{ __('Register') }}
                                    </button>
                                </div>
                            </div>
                        </form>
                    </div>
                </div>
            </div>
        </div>
    </div>
@endsection

vendor-login.blade.php

@extends('layouts.app')

@section('content')
    <div class="container">
        <div class="row justify-content-center">
            <div class="col-md-8">
                <div class="card">
                    <div class="card-header">{{ __('Vendor Login') }}</div>

                    <div class="card-body">
                        <form method="POST" action="{{ route('vendor.login.submit') }}">
                            @csrf

                            <div class="form-group row">
                                <label for="email" class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label>

                                <div class="col-md-6">
                                    <input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ old('email') }}" required autocomplete="email" autofocus>

                                    @error('email')
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $message }}</strong>
                                    </span>
                                    @enderror
                                </div>
                            </div>

                            <div class="form-group row">
                                <label for="password" class="col-md-4 col-form-label text-md-right">{{ __('Password') }}</label>

                                <div class="col-md-6">
                                    <input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" required autocomplete="current-password">

                                    @error('password')
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $message }}</strong>
                                    </span>
                                    @enderror
                                </div>
                            </div>

                            <div class="form-group row">
                                <div class="col-md-6 offset-md-4">
                                    <div class="form-check">
                                        <input class="form-check-input" type="checkbox" name="remember" id="remember" {{ old('remember') ? 'checked' : '' }}>

                                        <label class="form-check-label" for="remember">
                                            {{ __('Remember Me') }}
                                        </label>
                                    </div>
                                </div>
                            </div>

                            <div class="form-group row mb-0">
                                <div class="col-md-8 offset-md-4">
                                    <button type="submit" class="btn btn-primary">
                                        {{ __('Login') }}
                                    </button>

                                    @if (Route::has('password.request'))
                                        <a class="btn btn-link" href="{{ route('password.request') }}">
                                            {{ __('Forgot Your Password?') }}
                                        </a>
                                    @endif
                                </div>
                            </div>
                        </form>
                    </div>
                </div>
            </div>
        </div>
    </div>
@endsection

vendor-register.blade.php

@extends('layouts.app')

@section('content')
    <div class="container">
        <div class="row justify-content-center">
            <div class="col-md-8">
                <div class="card">
                    <div class="card-header">{{ __('Vendor Register') }}</div>

                    <div class="card-body">
                        <form method="POST" action="{{ route('vendor.register.submit') }}">
                            @csrf

                            <div class="form-group row">
                                <label for="name" class="col-md-4 col-form-label text-md-right">{{ __('Name') }}</label>

                                <div class="col-md-6">
                                    <input id="name" type="text" class="form-control @error('name') is-invalid @enderror" name="name" value="{{ old('name') }}" required autocomplete="name" autofocus>

                                    @error('name')
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $message }}</strong>
                                    </span>
                                    @enderror
                                </div>
                            </div>

                            <div class="form-group row">
                                <label for="email" class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label>

                                <div class="col-md-6">
                                    <input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ old('email') }}" required autocomplete="email">

                                    @error('email')
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $message }}</strong>
                                    </span>
                                    @enderror
                                </div>
                            </div>

                            <div class="form-group row">
                                <label for="password" class="col-md-4 col-form-label text-md-right">{{ __('Password') }}</label>

                                <div class="col-md-6">
                                    <input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" required autocomplete="new-password">

                                    @error('password')
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $message }}</strong>
                                    </span>
                                    @enderror
                                </div>
                            </div>

                            <div class="form-group row">
                                <label for="password-confirm" class="col-md-4 col-form-label text-md-right">{{ __('Confirm Password') }}</label>

                                <div class="col-md-6">
                                    <input id="password-confirm" type="password" class="form-control" name="password_confirmation" required autocomplete="new-password">
                                </div>
                            </div>

                            <div class="form-group row mb-0">
                                <div class="col-md-6 offset-md-4">
                                    <button type="submit" class="btn btn-primary">
                                        {{ __('Register') }}
                                    </button>
                                </div>
                            </div>
                        </form>
                    </div>
                </div>
            </div>
        </div>
    </div>
@endsection

Step 13: Set up the Dashboard pages for Admin & Vendor

We have come nearly to the end. We need to create dashboard or home pages for Admin & Vendor models. Now run the following command in your terminal or create manually:

$ touch resources/views/admin.blade.php
$ touch resources/views/vendor.blade.php

After creating pages write the below code for Admin & Vendor.

admin.blade.php

@extends('layouts.app')

@section('content')
    <div class="container">
        <div class="row justify-content-center">
            <div class="col-md-8">
                <div class="card">
                    <div class="card-header">Admin Dashboard</div>

                    <div class="card-body">
                        @if (session('status'))
                            <div class="alert alert-success" role="alert">
                                {{ session('status') }}
                            </div>
                        @endif

                        You are logged in as Admin!
                    </div>
                </div>
            </div>
        </div>
    </div>
@endsection

vendor.blade.php

@extends('layouts.app')

@section('content')
    <div class="container">
        <div class="row justify-content-center">
            <div class="col-md-8">
                <div class="card">
                    <div class="card-header">Vendor Dashboard</div>

                    <div class="card-body">
                        @if (session('status'))
                            <div class="alert alert-success" role="alert">
                                {{ session('status') }}
                            </div>
                        @endif

                        You are logged in as Vendor!
                    </div>
                </div>
            </div>
        </div>
    </div>
@endsection

Step 14: Set up the routes

Our application is almost ready. Let us define the routes to access all the pages we have created so far. Open the routes/web.php file and replace with the following:

<?php

use Illuminate\Support\Facades\Route;


Route::get('/', function () {
    return view('welcome');
});

Auth::routes();

Route::get('/home', 'HomeController@index')->name('home');

// Admin routes
Route::prefix('admin')->group(function(){
    Route::get('/', 'Users\Admin\AdminController@index')->name('admin.dashboard');
    Route::get('/login', 'Auth\AdminLoginController@showLoginForm')->name('admin.login');
    Route::post('/login', 'Auth\AdminLoginController@login')->name('admin.login.submit');
    Route::get('/register', 'Auth\AdminRegisterController@showRegisterForm')->name('admin.register');
    Route::post('/register', 'Auth\AdminRegisterController@register')->name('admin.register.submit');
});


// Vendor routes
Route::prefix('vendor')->group(function(){
    Route::get('/', 'Users\Vendor\VendorController@index')->name('vendor.dashboard');
    Route::get('/login', 'Auth\VendorLoginController@showLoginForm')->name('vendor.login');
    Route::post('/login', 'Auth\VendorLoginController@login')->name('vendor.login.submit');
    Route::get('/register', 'Auth\VendorRegisterController@showRegisterForm')->name('vendor.register');
    Route::post('/register', 'Auth\VendorRegisterController@register')->name('vendor.register.submit');
});

Step 15: Modify how our users are redirected if authenticated

It is important you modify how users are redirected when they are authenticated. Laravel by default redirects all authenticated users to /home. We will get the error below if we do not modify the redirection.

So, to solve that, open the app/Http/Controllers/Middleware/RedirectIfAuthenticated.php file and replace with this:

// app/Http/Controllers/Middleware/RedirectIfAuthenticated.php

<?php

namespace App\Http\Middleware;

use App\Providers\RouteServiceProvider;
use Closure;
use Illuminate\Support\Facades\Auth;

class RedirectIfAuthenticated
{

    public function handle($request, Closure $next, $guard = null)
    {
        if ($guard == "admin" && Auth::guard($guard)->check()) {
            return redirect()->route('admin.dashboard');
        }

        if ($guard == "vendor" && Auth::guard($guard)->check()) {
            return redirect()->route('vendor.dashboard');
        }

        if (Auth::guard($guard)->check()) {
            return redirect()->route('home');
        }

        return $next($request);
    }
}

The RedirectIfAuthenticated middleware receives the auth guard as a parameter. This middleware is triggered when we try to visit any page meant for authenticated users. We can then determine the type of authentication the user has and redirect them accordingly.

Step 16: Modify authentication exception handler

There is a little annoying thing that would happen when a user is redirected. You would expect that if a user tries to access say /vendor but is not authenticated, that the user is redirected to /vendor/login, yes? Well, they don’t. They get redirected to /login which is not what we want.

To ensure that when a user tries to visit /vendor they are redirected to /vendor/login or the same for /admin, we have to modify the exception handler. Open the handler file in app/Exceptions and add the following:

// app/Exceptions/Handler.php

<?php

namespace App\Exceptions;

use Illuminate\Auth\AuthenticationException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Throwable;

class Handler extends ExceptionHandler
{

    protected $dontReport = [
        //
    ];

    protected $dontFlash = [
        'password',
        'password_confirmation',
    ];

    public function report(Throwable $exception)
    {
        parent::report($exception);
    }

    public function render($request, Throwable $exception)
    {
        return parent::render($request, $exception);
    }

    protected function unauthenticated($request, AuthenticationException $exception)
    {

        if ($request->expectsJson()) {
            return response()->json(['error' => 'Unauthenticated.'], 401);
        }

        if ($request->is('admin') || $request->is('admin/*')) {
            return redirect()->guest(route('admin.login'));
        }

        if ($request->is('vendor') || $request->is('vendor/*')) {
            return redirect()->guest(route('vendor.login'));
        }

        return redirect()->guest(route('login'));
    }
}

The unauthenticated method we just added resolves this issue we have. It receives an AuthenticationExpection exception by default which carries that guard information.

Our workaround is to use request→is(). This checks the URL we are trying to access. It can also check the URL pattern if we do not have an absolute URL or if we have a route group.

In our case, we first check if we received a JSON request and handle the exception separately. Then we check if we are trying to access /admin or any URL preceded by admin. We redirect the user to the appropriate login page. We also do the check for vendor as well.

This is a good workaround for us, but it means we must know the absolute URL we want to access, or at least have the same prefix for all routes that will be protected by our guard.

Step 17: Run the application

Now that our application is ready, run the following command to get it up:

    $ php artisan serve

It should typically be available on http://localhost:8000 or  http://127.0.0.1:8000.

Remember to visit http://localhost:8000/vendor/register and http://localhost:8000/admin/register to register vendors and admins respectively. Then visit http://localhost:8000/vendor/login and http://localhost:8000/admin/login to login the vendors and admins respectively.

Conclusion

In this tutorial, we dived deep into Laravel authentication. We defined multiple guards to handle multiple authentications and access control. We also handle redirection for authenticated user and redirection for an unauthenticated user.

If you followed this guide thoroughly, you will be able to set up the base authentication for an application with different user classes (possibly a multitenant application). Be that as it may, try extending what you have seen and share what you come up with.

6 thoughts on “Laravel 7 Multi Authentication Tutorial

  1. increíble post, super útil y explicado. es posible encontrar el repositorio de éste ejemplo? sería la frutillita del postre. gracias!

  2. Yeah, that code is incomplete. The user actually doesn’t get logged in though RedirectIfAuthenticated will be successfully triggered. Try to get the name or id of the logged in user. You can’t because you’re not logged in.

Leave a Reply

Your email address will not be published. Required fields are marked *