How to Implement Multiple Authentication Guards in Laravel 10

How to Implement Multiple Authentication Guards in Laravel 10

In this post we will give you information about How to Implement Multiple Authentication Guards in Laravel 10. Hear we will give you detail about How to Implement Multiple Authentication Guards in Laravel 10 And how to use it also give you demo for it if it is necessary.

Eventually, we are going to learn how to create multiple auth (Authentication) in Laravel using guards, and we will also consider other laravel imperatives that are useful to build laravel basic auth app from starting.

In general, Authentication is the security process, and it indicates acknowledging the genuine user with proper account details.

We will develop two users one is an admin, and the other one is a regular user. Based on their roles, we will allow them to access in the app using middleware. Let us begin our work and start building our application.

How to Implement Multiple Authentication Guards in Laravel 10

Before starting the development, let us first see the video on how multi-guard authentication works. In our demo, we used two logins, one for the blogger and one for the admin.

Step 1: Install Laravel Project

First, open Terminal and run the following command to create a fresh laravel project:

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

or, if you have installed the Laravel Installer as a global composer dependency:

laravel new multi-guard-auth

Step 2: Install Laravel UI

Next, you need to run the below command in your terminal

composer require laravel/ui

Step 3: Setup Auth Scaffolding with Bootstrap 5

php artisan ui bootstrap --auth

 Step 4: Install NPM Dependencies

Run the following command to install frontend dependencies:

npm install

After the Update Of Laravel 10.20.0, Laravel replaces Webpack with Vite. You can follow this article for Setup Bootstrap 5 in Laravel 10.

Step 5. Configure Database Details:

After, Installation Go to the project root directory, open the .env file, and set database detail as follow:

DB_CONNECTION=mysql 
DB_HOST=127.0.0.1 
DB_PORT=3306 
DB_DATABASE=<DATABASE NAME>
DB_USERNAME=<DATABASE USERNAME>
DB_PASSWORD=<DATABASE PASSWORD>

Step 6: Create Migration and Model

Use the below command to create migration and Model for Admin and Blog

php artisan make:model Admin -m

-m the argument is used to create a migration file.

Update the migration file of the admin like the users’ migration table, or you can also extend the table by adding fields needed for the application.

Step 7: Define Guards

Guards define how the admin is authenticated for each request. Our application will have a guard Admin. after defining the guards set their providers. When we use these guards it tells what to use for authentication or validation. Open the Admin.php file in the app/Models folder. Update guard as admin and fillable array with field names.

<?php

namespace AppModels;

use IlluminateDatabaseEloquentFactoriesHasFactory;
use IlluminateFoundationAuthUser as Authenticatable;
use IlluminateDatabaseEloquentModel;

class Admin extends Authenticatable
{
    use HasFactory;

    protected $guard = "admin";

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

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

Open config/auth.php for adding guard. We’ve added one guard: admin and updated their provider’s array.

<?php

return [

    /*
    |--------------------------------------------------------------------------
    | 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"
    |
    */

    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],
        'admin' => [
            'driver' => 'session',
            'provider' => 'admins',
        ],
    ],

    /*
    |--------------------------------------------------------------------------
    | 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' => AppModelsUser::class,
        ],
        'admins' => [
            'driver' => 'eloquent',
            'model' => AppModelsAdmin::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 each reset token will 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,
        ],
    ],

    /*
    |--------------------------------------------------------------------------
    | Password Confirmation Timeout
    |--------------------------------------------------------------------------
    |
    | Here you may define the number 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 8: Set Up Controller

Open the LoginController in app/Http/Controllers/Auth and edit as follows:

<?php

namespace AppHttpControllersAuth;

use AppHttpControllersController;
use AppProvidersRouteServiceProvider;
use IlluminateFoundationAuthAuthenticatesUsers;

class LoginController extends Controller
{
    /*
    |--------------------------------------------------------------------------
    | Login Controller
    |--------------------------------------------------------------------------
    |
    | This controller handles authenticating users for the application and
    | redirecting them to your home screen. The controller uses a trait
    | to conveniently provide its functionality to your applications.
    |
    */

    use AuthenticatesUsers;

    /**
     * Where to redirect users after login.
     *
     * @var string
     */
    protected $redirectTo = RouteServiceProvider::HOME;

    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('guest')->except('logout');
        $this->middleware('guest:admin')->except('logout');
    }
}

We set the middleware to restrict access to this controller or its methods. It is important we defined all the different types of guests in the controller. This way, if one type of user is logged in and you try to use another user type to log in, it will redirect you to a predefined authentication page.

Now, define the login for admins:

app/Http/Controllers/Auth/LoginController.php

<?php

namespace AppHttpControllersAuth;

use AppHttpControllersController;
use AppProvidersRouteServiceProvider;
use IlluminateFoundationAuthAuthenticatesUsers;
use IlluminateHttpRequest;


class LoginController extends Controller
{
    /*
    |--------------------------------------------------------------------------
    | Login Controller
    |--------------------------------------------------------------------------
    |
    | This controller handles authenticating users for the application and
    | redirecting them to your home screen. The controller uses a trait
    | to conveniently provide its functionality to your applications.
    |
    */

    use AuthenticatesUsers;

    /**
     * Where to redirect users after login.
     *
     * @var string
     */
    protected $redirectTo = RouteServiceProvider::HOME;

    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('guest')->except('logout');
        $this->middleware('guest:admin')->except('logout');
    }

    public function showAdminLoginForm()
    {
        return view('auth.login', ['url' => route('admin.login-view'), 'title'=>'Admin']);
    }

    public function adminLogin(Request $request)
    {
        $this->validate($request, [
            'email'   => 'required|email',
            'password' => 'required|min:6'
        ]);

        if (Auth::guard('admin')->attempt($request->only(['email','password']), $request->get('remember'))){
            return redirect()->intended('/admin/dashboard');
        }

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

We have set up a method to return the login page for an admin. We will use the same page for all the user types and only change the URL they get sent to. Saves us a lot of code we could avoid writing.

We also defined the adminLogin the method which checks that the right credentials are supplied. Then we attempt to log a user in with the admin guard. It is important we set this guard when attempting a login so that the Auth facade will check the right table matching credentials. It will also set up our authentication so we can restrict pages based on the type of user who is logged in.

Step 9: Modify RegisterController

Open the RegisterController and edit as follows:

<?php

namespace AppHttpControllersAuth;

use AppHttpControllersController;
use AppProvidersRouteServiceProvider;
use AppModelsUser;
use IlluminateFoundationAuthRegistersUsers;
use IlluminateSupportFacadesHash;
use IlluminateSupportFacadesValidator;

class RegisterController extends Controller
{
    /*
    |--------------------------------------------------------------------------
    | Register Controller
    |--------------------------------------------------------------------------
    |
    | This controller handles the registration of new users as well as their
    | validation and creation. By default this controller uses a trait to
    | provide this functionality without requiring any additional code.
    |
    */

    use RegistersUsers;

    /**
     * Where to redirect users after registration.
     *
     * @var string
     */
    protected $redirectTo = RouteServiceProvider::HOME;

    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('guest');
        $this->middleware('guest:admin');
    }

    /**
     * Get a validator for an incoming registration request.
     *
     * @param  array  $data
     * @return IlluminateContractsValidationValidator
     */
    protected function validator(array $data)
    {
        return Validator::make($data, [
            'name' => ['required', 'string', 'max:255'],
            'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
            'password' => ['required', 'string', 'min:8', 'confirmed'],
        ]);
    }

    /**
     * Create a new user instance after a valid registration.
     *
     * @param  array  $data
     * @return AppModelsUser
     */
    protected function create(array $data)
    {
        return User::create([
            'name' => $data['name'],
            'email' => $data['email'],
            'password' => Hash::make($data['password']),
        ]);
    }
}

We have set up the middleware the controller will use, just like we did with the LoginController.

Now, let us set up the methods to return the registration pages for the admin:

<?php

namespace AppHttpControllersAuth;

use AppHttpControllersController;
use AppProvidersRouteServiceProvider;
use AppModelsUser;
use IlluminateFoundationAuthRegistersUsers;
use IlluminateSupportFacadesHash;
use IlluminateSupportFacadesValidator;

class RegisterController extends Controller
{
    /*
    |--------------------------------------------------------------------------
    | Register Controller
    |--------------------------------------------------------------------------
    |
    | This controller handles the registration of new users as well as their
    | validation and creation. By default this controller uses a trait to
    | provide this functionality without requiring any additional code.
    |
    */

    use RegistersUsers;

    /**
     * Where to redirect users after registration.
     *
     * @var string
     */
    protected $redirectTo = RouteServiceProvider::HOME;

    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('guest');
        $this->middleware('guest:admin');
    }

    /**
     * Get a validator for an incoming registration request.
     *
     * @param  array  $data
     * @return IlluminateContractsValidationValidator
     */
    protected function validator(array $data)
    {
        return Validator::make($data, [
            'name' => ['required', 'string', 'max:255'],
            'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
            'password' => ['required', 'string', 'min:8', 'confirmed'],
        ]);
    }

    /**
     * Create a new user instance after a valid registration.
     *
     * @param  array  $data
     * @return AppModelsUser
     */
    protected function create(array $data)
    {
        return User::create([
            'name' => $data['name'],
            'email' => $data['email'],
            'password' => Hash::make($data['password']),
        ]);
    }

    public function showAdminRegisterForm()
    {
        return view('auth.register', ['route' => route('admin.register-view'), 'title'=>'Admin']);
    }
}

Now, we can define our methods for creating an admin:

<?php

namespace AppHttpControllersAuth;

use AppHttpControllersController;
use AppProvidersRouteServiceProvider;
use AppModelsUser;
use AppModelsAdmin;
use IlluminateFoundationAuthRegistersUsers;
use IlluminateSupportFacadesHash;
use IlluminateSupportFacadesValidator;
use IlluminateHttpRequest;



class RegisterController extends Controller
{
    /*
    |--------------------------------------------------------------------------
    | Register Controller
    |--------------------------------------------------------------------------
    |
    | This controller handles the registration of new users as well as their
    | validation and creation. By default this controller uses a trait to
    | provide this functionality without requiring any additional code.
    |
    */

    use RegistersUsers;

    /**
     * Where to redirect users after registration.
     *
     * @var string
     */
    protected $redirectTo = RouteServiceProvider::HOME;

    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('guest');
        $this->middleware('guest:admin');
    }

    /**
     * Get a validator for an incoming registration request.
     *
     * @param  array  $data
     * @return IlluminateContractsValidationValidator
     */
    protected function validator(array $data)
    {
        return Validator::make($data, [
            'name' => ['required', 'string', 'max:255'],
            'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
            'password' => ['required', 'string', 'min:8', 'confirmed'],
        ]);
    }

    /**
     * Create a new user instance after a valid registration.
     *
     * @param  array  $data
     * @return AppModelsUser
     */
    protected function create(array $data)
    {
        return User::create([
            'name' => $data['name'],
            'email' => $data['email'],
            'password' => Hash::make($data['password']),
        ]);
    }

    public function showAdminRegisterForm()
    {
        return view('auth.register', ['route' => route('admin.register-view'), 'title'=>'Admin']);
    }

    protected function createAdmin(Request $request)
    {
        $this->validator($request->all())->validate();
        $admin = Admin::create([
            'name' => $request['name'],
            'email' => $request['email'],
            'password' => Hash::make($request['password']),
        ]);
        return redirect()->intended('admin');
    }
}

Step 10: Set up authentication pages

Open the resources/views/auth/login.blade.php file and edit as follows:

@extends('layouts.app')

@section('content')
<div >
    <div >
        <div >
            <div >
                <div >{{ $title ?? "" }} {{ __('Login') }}</div>

                <div >
                    @isset($route)
                        <form method="POST" action="{{ $route }}">
                    @else
                        <form method="POST" action="{{ route('login') }}">
                    @endisset
                    
                        @csrf

                        <div >
                            <label for="email" >{{ __('Email Address') }}</label>

                            <div >
                                <input id="email" type="email"  name="email" value="{{ old('email') }}" required autocomplete="email" autofocus>

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

                        <div >
                            <label for="password" >{{ __('Password') }}</label>

                            <div >
                                <input id="password" type="password"  name="password" required autocomplete="current-password">

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

                        <div >
                            <div >
                                <div >
                                    <input  type="checkbox" name="remember" id="remember" {{ old('remember') ? 'checked' : '' }}>

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

                        <div >
                            <div >
                                <button type="submit" >
                                    {{ __('Login') }}
                                </button>

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

We are checking if we passed a route parameter to the page when we called it. If we did, we modify the form’s action to use the route parameter. We also modified the header of the form so that it shows the type of user based on their login parameter.

Open the resources/views/auth/register.blade.php file and edit as follows:

@extends('layouts.app')

@section('content')
<div >
    <div >
        <div >
            <div >
                <div >{{ $title ?? "" }} {{ __('Register') }}</div>

                <div >
                    @isset($route)
                        <form method="POST" action="{{ $route }}">
                    @else
                        <form method="POST" action="{{ route('register') }}">
                    @endisset
                        @csrf

                        <div >
                            <label for="name" >{{ __('Name') }}</label>

                            <div >
                                <input id="name" type="text"  name="name" value="{{ old('name') }}" required autocomplete="name" autofocus>

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

                        <div >
                            <label for="email" >{{ __('Email Address') }}</label>

                            <div >
                                <input id="email" type="email"  name="email" value="{{ old('email') }}" required autocomplete="email">

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

                        <div >
                            <label for="password" >{{ __('Password') }}</label>

                            <div >
                                <input id="password" type="password"  name="password" required autocomplete="new-password">

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

                        <div >
                            <label for="password-confirm" >{{ __('Confirm Password') }}</label>

                            <div >
                                <input id="password-confirm" type="password"  name="password_confirmation" required autocomplete="new-password">
                            </div>
                        </div>

                        <div >
                            <div >
                                <button type="submit" >
                                    {{ __('Register') }}
                                </button>
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

We replicated what we did for the login page here.

Step 11: Create the pages for authenticated users

Now that we are done setting up the login and register page, let us make the page the admin will see when they are authenticated. Open the terminal and run the following commands to create a new file. Next, we will insert the corresponding code snippets into the files.

touch resources/views/admin.blade.php

Next, insert this code block into the resources/views/admin.blade.php file:

@extends('layouts.app')

@section('content')
<div >
    <div >
        <div >
            <div >
                <div >{{ __('Dashboard') }}</div>

                <div >
                    @if (session('status'))
                        <div  role="alert">
                            {{ session('status') }}
                        </div>
                    @endif

                    Hello Admin!
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

Finally, open the resources/views/home.blade.php file and replace with the following:

@extends('layouts.app')

@section('content')
<div >
    <div >
        <div >
            <div >
                <div >{{ __('Dashboard') }}</div>

                <div >
                    @if (session('status'))
                        <div  role="alert">
                            {{ session('status') }}
                        </div>
                    @endif

                    Hello User!
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

Step 12: Set up the routes

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 IlluminateSupportFacadesRoute;

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

use AppHttpControllersAuthLoginController;
use AppHttpControllersAuthRegisterController;

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

Auth::routes();

Route::get('/admin',[LoginController::class,'showAdminLoginForm'])->name('admin.login-view');
Route::post('/admin',[LoginController::class,'adminLogin'])->name('admin.login');

Route::get('/admin/register',[RegisterController::class,'showAdminRegisterForm'])->name('admin.register-view');
Route::post('/admin/register',[RegisterController::class,'createAdmin'])->name('admin.register');

Route::get('/home', [AppHttpControllersHomeController::class, 'index'])->name('home');
Route::get('/admin/dashboard',function(){
    return view('admin');
})->middleware('auth:admin');

Step 13: Modify RedirectIfAuthenticated.php Middleware

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.

open the app/Http/Controllers/Middleware/RedirectIfAuthenticated.php file and replace with this:

<?php

namespace AppHttpMiddleware;

use AppProvidersRouteServiceProvider;
use Closure;
use IlluminateHttpRequest;
use IlluminateSupportFacadesAuth;

class RedirectIfAuthenticated
{
    /**
     * Handle an incoming request.
     *
     * @param  IlluminateHttpRequest  $request
     * @param  Closure(IlluminateHttpRequest): (IlluminateHttpResponse|IlluminateHttpRedirectResponse)  $next
     * @param  string|null  ...$guards
     * @return IlluminateHttpResponse|IlluminateHttpRedirectResponse
     */
    public function handle(Request $request, Closure $next, ...$guards)
    {
        $guards = empty($guards) ? [null] : $guards;

        foreach ($guards as $guard) {

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

            if (Auth::guard($guard)->check()) {
                return redirect(RouteServiceProvider::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.

Step 14: Modify authentication exception handler

Open the handler file  app/Exceptions/Handler.php and add the following:

<?php

namespace AppExceptions;

use IlluminateFoundationExceptionsHandler as ExceptionHandler;
use IlluminateAuthAuthenticationException;
use Throwable;

class Handler extends ExceptionHandler
{
    /**
     * A list of exception types with their corresponding custom log levels.
     *
     * @var array<class-string<Throwable>, PsrLogLogLevel::*>
     */
    protected $levels = [
        //
    ];

    /**
     * A list of the exception types that are not reported.
     *
     * @var array<int, class-string<Throwable>>
     */
    protected $dontReport = [
        //
    ];

    /**
     * A list of the inputs that are never flashed to the session on validation exceptions.
     *
     * @var array<int, string>
     */
    protected $dontFlash = [
        'current_password',
        'password',
        'password_confirmation',
    ];

    /**
     * Register the exception handling callbacks for the application.
     *
     * @return void
     */
    public function register()
    {
        $this->reportable(function (Throwable $e) {
            //
        });
    }

    protected function unauthenticated($request, AuthenticationException $exception)
    {
        if ($request->expectsJson()) {
            return response()->json(['message' => 'Unauthenticated.'], 401);
        }

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

The unauthenticated the 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 any URL preceded by admin. We redirect the user to the appropriate login page.

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 15: Run the application

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

php artisan serve

Most Probably Application URL will be http://localhost:8000.

Remember to visit http://localhost:8000/admin and http://localhost:8000/admin/register.

Conclusion

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

The source code to the application in this article is available on Github.

Thank you for reading this blog.

Also see: How to Create Custom Validation Rules in Laravel 10

  .       .

If you have any queries or doubts about this topic please feel free to contact us. We will try to reach you.

Hope this code and post will helped you for implement How to Implement Multiple Authentication Guards in Laravel 10. if you need any help or any feedback give it in comment section or you have good idea about this post you can give it comment section. Your comment will help us for help you more and improve us. we will give you this type of more interesting post in featured also so, For more interesting post and code Keep reading our blogs

For More Info See :: laravel And github

We're accepting well-written guest posts and this is a great opportunity to collaborate : Contact US