Multi-User Authentication with Laravel | Simple Approach

Hanie Asemi
4 min readDec 20, 2023

--

Sometimes, there is a need to accommodate diverse user types with varying roles and permissions in the application. These types of users have different expectations of the application based on their roles, for example, consider two user and admin types of users. Different approaches can be taken to handle multi-guard authentication in Laravel. In this blog, the first and easiest approach will be discussed.

Multi-User Authentication with Laravel | Simple Approach

Database Design

First of all, we need to dedicate our database structure. In this method, just one table is responsible for saving the information of users, this table will contain a role column with an integer type to indicate the role of the user.

The structure of the users_table

Project Initialization

Secondly, clone this GitHub repository, and follow the steps to run the project with Docker in the localhost. You can check the whole steps in this blog.

Multi-Authentication Code Implementation

Finally, we will implement two types of users to be authenticated, the first user is an admin and the second one is just a simple user, to get the multi-guard feature implemented, follow these steps:

  1. Create the user migration by running this command:
docker compose exec app php artisan make:migration create_users_table

2. The created migration will contain the below code structure.

public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->integer('role');
$table->string('email')->unique();
$table->string('password');
$table->timestamps();
});
}

3. By default you have a User model in the app/Models directory of the project so edit the fillable attribute of the model to support the role column of the table, then add role constant to the model.


const ROLE_ADMIN = 1;
const ROLE_USER = 2;

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

4. Actually, we don’t have real users to get this project work and we have to add a seeder to create a list of different types of users. Create the UserSeeder class to seed some users' data.

class UserSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
$users = [
[
'email' => 'admin@gmail.com',
'password' => Hash::make(1234567),
'role' => User::ROLE_ADMIN
],[
'email' => 'user@gmail.com',
'password' => Hash::make(1234567),
'role' => User::ROLE_USER
]
];
User::query()->insert($users);
}
}
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*
* @return void
*/
public function run(): void
{
$this->call(UserSeeder::class);
}
}

Finally, run docker compose exec app php artisan db:seed

5. Install Passport

In this step, we need the Passport package to be installed. Follow all steps in this documentation to do so. Finally, update the User model to use the Laravel\Passport\HasApiTokens trait.

6. Define Authentication Guards in the config/auth.php

 'guards' => [
'api' => [
'driver' => 'passport',
'provider' => 'users',
],
],

7. Login User

In the next step, need to create a controller and define a route for handling the login action. The route/api.php and the LoginController will have the below codes:

class LoginController extends Controller
{
public function __invoke(Request $request): JsonResponse
{
/** @var User $user */
$user = User::query()->where('email', $request->get('email'))->first();
if (empty($user)) {
return response()->json([
'message' => 'The user does not exist'
]);
}
if (Hash::check($request->get('password'), $user->password)) {
return response()->json([
'message' => 'success',
'user' => $user,
'token' => $user->createToken('Laravel Personal Access Client')->accessToken
]);
}
return response()->json([
'message' => 'Email or password are wrong'
], 422);
}
}
Route::middleware('guest')->group(function () {
Route::post('login', LoginController::class);
});

8. Create Middleware

To handle the permissions of the users we have to create middleware and add to the routes which need specific access and permission. In this blog we will make two differents middleware to overcome this requirement, The first one is the AdminMiddleware that will add to the routes that are allowed for admins and the second one is UserMiddleware which will define the accessable routes for usual users. Actually you can create a single middleware and handle all these tasks there, but if it is better to respect the principle of Single Responsiblity and avoid doing so, because as your project goes larg this class will need to handle more roles and permissions as well. Here is the code of created middlewares:

class AdminMiddleware
{

public function handle(Request $request, Closure $next): Response
{
if (auth()->check() && auth()->user()->role === User::ROLE_ADMIN) {
return $next($request);
}
return response()->json([
'message' => 'Unauthenticated'
], 401);
}
}
class UserMiddleware
{
public function handle(Request $request, Closure $next): Response
{
if (auth()->check() && auth()->user()->role === User::ROLE_USER) {
return $next($request);
}
return response()->json([
'message' => 'Unauthenticated'
], 401);
}
}

After definition of middlewares, the $routeMiddleware attribute of the app/Http/Kernel.php will update as below:

 protected $routeMiddleware = [
'admin' => AdminMiddleware::class,
'user' => UserMiddleware::class,
]

9. Limit Routes Accessiblity by Middleware

There are some routes that are accessable for just admins, also may have some routes for users. For example, the admin/dashboard should be protected of users access such as user/dahsboard which should not pass an admin.

Route::middleware('auth')->group(function () {
Route::middleware('admin')->group(function () {
Route::get('admin/dashboard', function () {
return response()->json(['message' => 'welcome, this is admin!']);
});
});
Route::middleware('user')->group(function () {
Route::get('user/dashboard', function () {
return response()->json(['message' => 'welcome, this is user!']);
});
});
});

To sum it up, the multi-authentication is one of the basic requirements of an application and we cover that as simple as possible, but consider if your project grows you will need more types of users to be authenticated, so this described will not a good choice to handle it.

--

--

Hanie Asemi
Hanie Asemi

Written by Hanie Asemi

A forward-looking programmer who loves writing and learning

No responses yet