Step 1:
Installation of Laravel Livewire and Jetstream Package
For you to install jetstream and laravel together run the following command
laravel new laravelmultiauth --jet
Once the installation is done run the following
npm install && npm run dev
create a database, you can give it a name you prefer and run the following command to migrate the tables
php artisan migrate
and finally, run the following command php artisan serve to run the application in your local environment
Step 2:
Admins Table and Migration
Start by creating an admin controller, so run this command
php artisan make:controller AdminController
Let’s also create a model and a migration file table for admin by running this command
php artisan make:model Admin -m
copy the contents the of user table to admins since we are creating a similar authentication for admin. So you should
have something like this in the admin’s table
//…_create_admins_table.php
Schema::create('admins', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->foreignId('current_team_id')->nullable();
$table->string('profile_photo_path', 2048)->nullable();
$table->timestamps();
});
as well as copy the contents of the user.php model to the admin.php model therefore you should have something like this…
Admin.php
class Admin extends Authenticatable
{
use HasApiTokens;
use HasFactory;
use HasProfilePhoto;
use Notifiable;
use TwoFactorAuthenticatable;
/**
* The attributes that are mass assignable.
*
* @var string[]
*/
protected $fillable = [
'name',
'email',
'password',
];
/**
* The attributes that should be hidden for serialization.
*
* @var array
*/
protected $hidden = [
'password',
'remember_token',
'two_factor_recovery_codes',
'two_factor_secret',
];
/**
* The attributes that should be cast.
*
* @var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
/**
* The accessors to append to the model's array form.
*
* @var array
*/
protected $appends = [
'profile_photo_url',
];
}
good!. Now run this command //php artisan migrate to migrate the admin’s table we just created earlier.
Step 3:
Seed Admins Data
Now here we will create an admin factory that will help us to seed data into the admin’s table.
Learn more about factories in laravel here. Ok, run this command php artisan make:factory AdminFactory.
After that copy the items from UserFactory.php to the newly created AdminFactory.php and change the first two fields’ name and email so the output should look like this
AdminFactory.php
'name' => 'Admin',
'email' => 'admin@admin.com',
'email_verified_at' => now(),
'password' => bcrypt('password123'), // password
'remember_token' => Str::random(10),
then don’t forget to add //use Illuminate\Support\Str; from the UserFactory.php to AdminFactory.php since we are using the //Str::random for remembering token.
Lastly, go to seeders -> DatabaseSeeder.php and change the following in the public function run
\App\Models\User::factory(10)->create(); to \App\Models\Admin::factory()->create();
so that it will call the Admin model we created earlier and seed our admins’ table. So now run the command
php artisan migrate --seed
Step 4:
Guards For Admins
In this step, we will create guards for admins, so go to the config and locate the auth.php and update like below
Authentication Guards:
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'admin' => [
'driver' => 'session',
'provider' => 'admins',
],
],
and also update the providers
User Providers:
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
'admins' => [
'driver' => 'eloquent',
'model' => App\Models\Admin::class,
],
for passwords update them as follows
Resetting Passwords:
'passwords' => [
'users' => [
'provider' => 'users',
'table' => 'password_resets',
'expire' => 60,
'throttle' => 60,
],
'admins' => [
'provider' => 'admins',
'table' => 'password_resets',
'expire' => 60,
'throttle' => 60,
],
],
Once that is done. Open this controller //AuthenticatedSessionController.php. This controller manages the guards i.e the
login and logout session for your app, currently, we are using the web guard. So I want us to update it to use admin guard too.
You can check which guard the controller is using from the constructor by //dd($this->guard) it will give you the default
guard your application is using.
public function __construct(StatefulGuard $guard)
{
$this->guard = $guard;
dd($this->guard); // default guard is the web guard
}
Ex:
Illuminate\Auth\SessionGuard {#415 ▼
#name: "web"
#lastAttempted: null
#viaRemember: false
#rememberDuration: 2628000
#session: Illuminate\Session\Store {#424 ▶}
#cookie: Illuminate\Cookie\CookieJar {#425 ▶}
#request: Illuminate\Http\Request {#43 ▶}
#events: Illuminate\Events\Dispatcher {#27 ▶}
#loggedOut: false
#recallAttempted: false
#user: null
#provider: Illuminate\Auth\EloquentUserProvider {#410 ▶}
Now go to this file Providers->FortifyServiceProvider.php and register the following classes
AdminController.php from the controller, RedirectIfTwoFactorAuthenticatable::class and AttemptToAuthenticate::class from AuthenticatedSessionController.php
so that when the controller runs it can also load the other sessions for the admin
FortifyServiceProvider.php
….
public function register()
{
$this->app->when([AdminController::class, AttemptToAuthenticate::class,public function register()
{
$this->app->when([AdminController::class, AttemptToAuthenticate::class,
RedirectIfTwoFactorAuthenticatable::class]);
}
….
You also need to update the same function with the statefulguard from AuthenticatedSessionController.php and return the
guard for admin like this
FortifyServiceProvider.php
….
public function register()
{
$this->app->when([AdminController::class, AttemptToAuthenticate::class,
RedirectIfTwoFactorAuthenticatable::class])
->needs(StatefulGuard::class)
->give(function() {
return Auth::guard('admin');
});
}
….
since we are using the above classes you need to use the following lines of code i.e copy the following from
AuthenticatedSessionController.php to FortifyServiceProvider.php
use App\Actions\Fortify\AttemptToAuthenticate;
use App\Actions\Fortify\RedirectIfTwoFactorAuthenticatable;
use Illuminate\Contracts\Auth\StatefulGuard;
use App\Http\controllers\AdminController;
Once it’s done I want to create a statefulguard for admin just like we have for users. So go to the app make a folder rename
it app->Guards->AdminStatefulGuard.php in this file copy the contents from the normal statefulguard to AdminStatefulGuard.php
AdminStatefulGuard.php
<?php
namespace App\Guards; // change like this
interface AdminStatefulGuard extends Guard // change like this
{
/**
* Attempt to authenticate a user using the given credentials.
*
* @param array $credentials
* @param bool $remember
* @return bool
*/
public function attempt(array $credentials = [], $remember = false);
/**
* Log a user into the application without sessions or cookies.
*
* @param array $credentials
* @return bool
*/
public function once(array $credentials = []);
/**
* Log a user into the application.
*
* @param \Illuminate\Contracts\Auth\Authenticatable $user
* @param bool $remember
* @return void
*/
public function login(Authenticatable $user, $remember = false);
/**
* Log the given user ID into the application.
*
* @param mixed $id
* @param bool $remember
* @return \Illuminate\Contracts\Auth\Authenticatable|bool
*/
public function loginUsingId($id, $remember = false);
/**
* Log the given user ID into the application without sessions or cookies.
*
* @param mixed $id
* @return \Illuminate\Contracts\Auth\Authenticatable|bool
*/
public function onceUsingId($id);
/**
* Determine if the user was authenticated via "remember me" cookie.
*
* @return bool
*/
public function viaRemember();
/**
* Log the user out of the application.
*
* @return void
*/
public function logout();
}
Step 5:
In this step, we start by copying the contents of AuthenticatedSessionController.php to AdminController and editing a few things and it should look like this.
AdminController.php
<?php
namespace App\Http\Controllers; // remember to update the namespace like this
use Illuminate\Contracts\Auth\StatefulGuard;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Illuminate\Routing\Pipeline;
use App\Actions\Fortify\AttemptToAuthenticate;// update to this
use Laravel\Fortify\Actions\EnsureLoginIsNotThrottled;
use Laravel\Fortify\Actions\PrepareAuthenticatedSession;
use App\Actions\Fortify\RedirectIfTwoFactorAuthenticatable; // update to this
//use Laravel\Fortify\Contracts\LoginResponse;
use App\Http\Responses\LoginResponse; // change to this, will create later
use Laravel\Fortify\Contracts\LoginViewResponse;
use Laravel\Fortify\Contracts\LogoutResponse;
use Laravel\Fortify\Features;
use Laravel\Fortify\Fortify;
use Laravel\Fortify\Http\Requests\LoginRequest;
class AdminController extends Controller
{
/**
* The guard implementation.
*
* @var \Illuminate\Contracts\Auth\StatefulGuard
*/
protected $guard;
/**
* Create a new controller instance.
*
* @param \Illuminate\Contracts\Auth\StatefulGuard $guard
* @return void
*/
public function __construct(StatefulGuard $guard)
{
$this->guard = $guard;
}
/**
* Show the login view.
*
* @param \Illuminate\Http\Request $request
* @return \Laravel\Fortify\Contracts\LoginViewResponse
*/
public function create(Request $request): LoginViewResponse
{
return app(LoginViewResponse::class);
}
/**
* Attempt to authenticate a new session.
*
* @param \Laravel\Fortify\Http\Requests\LoginRequest $request
* @return mixed
*/
public function store(LoginRequest $request)
{
return $this->loginPipeline($request)->then(function ($request) {
return app(LoginResponse::class);
});
}
/**
* Get the authentication pipeline instance.
*
* @param \Laravel\Fortify\Http\Requests\LoginRequest $request
* @return \Illuminate\Pipeline\Pipeline
*/
protected function loginPipeline(LoginRequest $request)
{
if (Fortify::$authenticateThroughCallback) {
return (new Pipeline(app()))->send($request)->through(array_filter(
call_user_func(Fortify::$authenticateThroughCallback, $request)
));
}
if (is_array(config('fortify.pipelines.login'))) {
return (new Pipeline(app()))->send($request)->through(array_filter(
config('fortify.pipelines.login')
));
}
return (new Pipeline(app()))->send($request)->through(array_filter([
config('fortify.limiters.login') ? null : EnsureLoginIsNotThrottled::class,
Features::enabled(Features::twoFactorAuthentication()) ? RedirectIfTwoFactorAuthenticatable::class : null,
AttemptToAuthenticate::class,
PrepareAuthenticatedSession::class,
]));
}
/**
* Destroy an authenticated session.
*
* @param \Illuminate\Http\Request $request
* @return \Laravel\Fortify\Contracts\LogoutResponse
*/
public function destroy(Request $request): LogoutResponse
{
$this->guard->logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
return app(LogoutResponse::class);
}
}
Now go to the web.php route and update it as follows…
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\AdminController;
/*
|--------------------------------------------------------------------------
| 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!
|
*/
Route::get('/', function () {
return view('welcome');
});
Route::group(['prefix' =>'admin','middleware'=>['admin:admin']],function() {
Route::get('/login', [AdminController::class, 'loginform']);
Route::post('/login', [AdminController::class, 'store'])->name('admin.login');
});
Route::middleware(['auth:sanctum, admin', 'verified'])->get('/admin/dashboard', function () {
return view('dashboard');
})->name('dashboard');
Route::middleware(['auth:sanctum, web', 'verified'])->get('/dashboard', function () {
return view('dashboard');
})->name('dashboard');
after this create a guard in AdminController.php below (public function construct) for admin using the login form method and it should be like this
AdminController.php
public function loginform()
{
return view('auth.login',['guard' => 'admin']);
}
and then since we want to return a login blade like the default one we have for the user. Go to loginblade.php for user and update it as follows
loginblade.php
<form method="POST" action="{{ isset($guard) ? url($guard. '/login') :
route('login') }}">
@csrf
what this does will either redirect you to the default user normal login page or if you append it with admin like
/admin/login will take you to the admin login blade.
The next step is to copy these two files from …vendor/laravel/fortify/src/actions/redirectiftwofactorauthenticatable.php and
…vendor/laravel/fortify/src/actions/attempttoauthenticate.php to app/actions/fortify/… and edit them as below
AttemptToAuthenticate.php
<?php
namespace App\Actions\Fortify; // update the namespace only
use Illuminate\Auth\Events\Failed;
use Illuminate\Contracts\Auth\StatefulGuard;
use Illuminate\Validation\ValidationException;
use Laravel\Fortify\Fortify;
use Laravel\Fortify\LoginRateLimiter;
class AttemptToAuthenticate
{
/**
* The guard implementation.
*
* @var \Illuminate\Contracts\Auth\StatefulGuard
*/
protected $guard;
/**
* The login rate limiter instance.
*
* @var \Laravel\Fortify\LoginRateLimiter
*/
protected $limiter;
/**
* Create a new controller instance.
*
* @param \Illuminate\Contracts\Auth\StatefulGuard $guard
* @param \Laravel\Fortify\LoginRateLimiter $limiter
* @return void
*/
public function __construct(StatefulGuard $guard, LoginRateLimiter $limiter)
{
$this->guard = $guard;
$this->limiter = $limiter;
}
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @param callable $next
* @return mixed
*/
public function handle($request, $next)
{
if (Fortify::$authenticateUsingCallback) {
return $this->handleUsingCustomCallback($request, $next);
}
if ($this->guard->attempt(
$request->only(Fortify::username(), 'password'),
$request->boolean('remember'))
) {
return $next($request);
}
$this->throwFailedAuthenticationException($request);
}
/**
* Attempt to authenticate using a custom callback.
*
* @param \Illuminate\Http\Request $request
* @param callable $next
* @return mixed
*/
protected function handleUsingCustomCallback($request, $next)
{
$user = call_user_func(Fortify::$authenticateUsingCallback, $request);
if (! $user) {
$this->fireFailedEvent($request);
return $this->throwFailedAuthenticationException($request);
}
$this->guard->login($user, $request->boolean('remember'));
return $next($request);
}
/**
* Throw a failed authentication validation exception.
*
* @param \Illuminate\Http\Request $request
* @return void
*
* @throws \Illuminate\Validation\ValidationException
*/
protected function throwFailedAuthenticationException($request)
{
$this->limiter->increment($request);
throw ValidationException::withMessages([
Fortify::username() => [trans('auth.failed')],
]);
}
/**
* Fire the failed authentication attempt event with the given arguments.
*
* @param \Illuminate\Http\Request $request
* @return void
*/
protected function fireFailedEvent($request)
{
event(new Failed(config('fortify.guard'), null, [
Fortify::username() => $request->{Fortify::username()},
'password' => $request->password,
]));
}
}
RedirectIfTwoFactorAuthenticatable.php
<?php
namespace App\Actions\Fortify; // update the namespace only
use Illuminate\Auth\Events\Failed;
use Illuminate\Contracts\Auth\StatefulGuard;
use Illuminate\Validation\ValidationException;
use Laravel\Fortify\Fortify;
use Laravel\Fortify\LoginRateLimiter;
use Laravel\Fortify\TwoFactorAuthenticatable;
class RedirectIfTwoFactorAuthenticatable
{
/**
* The guard implementation.
*
* @var \Illuminate\Contracts\Auth\StatefulGuard
*/
protected $guard;
/**
* The login rate limiter instance.
*
* @var \Laravel\Fortify\LoginRateLimiter
*/
protected $limiter;
/**
* Create a new controller instance.
*
* @param \Illuminate\Contracts\Auth\StatefulGuard $guard
* @param \Laravel\Fortify\LoginRateLimiter $limiter
* @return void
*/
public function __construct(StatefulGuard $guard, LoginRateLimiter $limiter)
{
$this->guard = $guard;
$this->limiter = $limiter;
}
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @param callable $next
* @return mixed
*/
public function handle($request, $next)
{
$user = $this->validateCredentials($request);
if (optional($user)->two_factor_secret &&
in_array(TwoFactorAuthenticatable::class, class_uses_recursive($user))) {
return $this->twoFactorChallengeResponse($request, $user);
}
return $next($request);
}
/**
* Attempt to validate the incoming credentials.
*
* @param \Illuminate\Http\Request $request
* @return mixed
*/
protected function validateCredentials($request)
{
if (Fortify::$authenticateUsingCallback) {
return tap(call_user_func(Fortify::$authenticateUsingCallback, $request), function ($user) use ($request) {
if (! $user) {
$this->fireFailedEvent($request);
$this->throwFailedAuthenticationException($request);
}
});
}
$model = $this->guard->getProvider()->getModel();
return tap($model::where(Fortify::username(), $request->{Fortify::username()})->first(), function ($user) use ($request) {
if (! $user || ! $this->guard->getProvider()->validateCredentials($user, ['password' => $request->password])) {
$this->fireFailedEvent($request, $user);
$this->throwFailedAuthenticationException($request);
}
});
}
/**
* Throw a failed authentication validation exception.
*
* @param \Illuminate\Http\Request $request
* @return void
*
* @throws \Illuminate\Validation\ValidationException
*/
protected function throwFailedAuthenticationException($request)
{
$this->limiter->increment($request);
throw ValidationException::withMessages([
Fortify::username() => [trans('auth.failed')],
]);
}
/**
* Fire the failed authentication attempt event with the given arguments.
*
* @param \Illuminate\Http\Request $request
* @param \Illuminate\Contracts\Auth\Authenticatable|null $user
* @return void
*/
protected function fireFailedEvent($request, $user = null)
{
event(new Failed(config('fortify.guard'), $user, [
Fortify::username() => $request->{Fortify::username()},
'password' => $request->password,
]));
}
/**
* Get the two factor authentication enabled response.
*
* @param \Illuminate\Http\Request $request
* @param mixed $user
* @return \Symfony\Component\HttpFoundation\Response
*/
protected function twoFactorChallengeResponse($request, $user)
{
$request->session()->put([
'login.id' => $user->getKey(),
'login.remember' => $request->filled('remember'),
]);
return $request->wantsJson()
? response()->json(['two_factor' => true])
: redirect()->route('two-factor.login');
}
}
Step 6:
In this step, we start by updating the RouteServiceprovider.php since it has the guard for users with admin as well.
So go to Providers->RouteServiceProvider.php and update it as follows
RouteServiceProvider.php
public const HOME = '/dashboard';
public static function redirectTo($guard){
return $guard. '/dashboard';
}
then go to middleware->RedirectIfAuthenticated.php and update it with return $guard. ‘/dashboard’ as follows
RedirectIfAuthenticated.php
public function handle(Request $request, Closure $next, …$guards)
{
$guards = empty($guards) ? [null] : $guards;
foreach ($guards as $guard) {
if (Auth::guard($guard)->check()) {
return redirect($guard. '/dashboard'); // change like this
}
}
return $next($request);
}
}
Now create another middleware for admin, so here you will copy and change the RedirectIfAuthenticated.php to
AdminRedirectIfAuthenticated.php for admin and edit some few things. What you need to do is to copy and paste the contents
from RedirectIfAuthenticated.php to AdminRedirectIfAuthenticated.php and finally register the middleware.
AdminRedirectIfAuthenticated.php
<?php
namespace App\Http\Middleware;
use App\Providers\RouteServiceProvider;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class AdminRedirectIfAuthenticated
{
/**
* 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()) {
return redirect($guard. '/dashboard');
}
}
return $next($request);
}
}
register the middleware in the kernel.php. So you should have something like this…
kernel.php
protected $routeMiddleware = [
'admin' => \App\Http\Middleware\AdminRedirectIfAuthenticated::class,
….
….
];
the next step is to create a LoginResponse.php just like the one for the user which redirects the admin to his page after being logged in.
Make a folder Responses under the app->http and create a LoginResponse.php then copy the code from User LoginResponse.php
into the newly created LoginResponse for admin. Do like this app->Http->Responses->LoginResponse.php
LoginResponse.php for (admin)
<?php
namespace App\Http\Responses;
use Laravel\Fortify\Contracts\LoginResponse as LoginResponseContract;
use Laravel\Fortify\Fortify;
class LoginResponse implements LoginResponseContract
{
/**
* Create an HTTP response that represents the object.
*
* @param \Illuminate\Http\Request $request
* @return \Symfony\Component\HttpFoundation\Response
*/
public function toResponse($request)
{
return $request->wantsJson()
? response()->json(['two_factor' => false])
: redirect()->intended('admin/dashboard'); change like this
}
}
This is the LoginResponse I told you we would create later. Make sure you already updated AdminController.php with this
line of code use App\Http\Responses\LoginResponse; which calls for admin to be logged in.
Now go ahead and test everything to make sure it’s working If not check the code in GitHub to verify where you might have gone wrong. Remember to use Illuminate\Support\Facades\Auth; above the FortifyServiceProvider.php for authentication if an error is thrown.




Watch this tutorial on my YouTube Channel and subscribe…
I ѡas recommended this website by my cousin. I’m not sure
whether this post is written by him as no one else know such
detailed about my trouble. You are wonderful! Tһanks!
You’re highly welcome!
Thank you so much.
Thanks.
Thank you so much.
Hi, I am using WordPress.