Effortless Multi-Authentication with Laravel Sanctum: A Swift Guide for Seamless Implementation
Table of contents
Introduction
Creating a system with multiple authentications using Laravel Sanctum may seem challenging, requiring modifications to your config/app.php configuration file. However, a quick and easy solution exists to achieve your goal. This article demonstrates how to implement multiple authentications with Laravel Sanctum.
Prerequisites
Before you delve into Laravel Sanctum, ensure you have the following prerequisites:
Laravel Project: Set up a Laravel project either on your local environment or a server.
Composer: Make sure you have Composer installed, as it's essential for managing Laravel packages.
Basic Laravel Knowledge: Having a grasp of Laravel concepts such as routes, controllers, and migrations will prove helpful.
After installing a fresh instance of Laravel, the next step involves creating models for the users you plan to authenticate. For instance, consider the roles of students and teachers. Now, proceed to generate models and migrations for both the student and teacher entities.
php artisan make:model Student -m
php artisan make:model Teacher -m
Next, set up the Student and Teacher models by extending the Authenticatable class and incorporating the HasApiTokens trait.
Your models should now appear as follows:
/** Student Model */
class Student extends Authenticatable
{
use HasApiTokens;
}
/** Teacher Model */
class Teacher extends Authenticatable
{
use HasApiTokens;
}
Let's proceed by adding columns to both the students' and teachers' tables.
/** Student Table*/
public function up(): void
{
Schema::create('students', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->decimal('password');
$table->timestamps();
});
}
/** Teacher Table*/
public function up(): void
{
Schema::create('teachers', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->decimal('password');
$table->timestamps();
});
}
We are now ready to implement the authentication logic. Create two separate controllers: StudentAuthController and TeacherAuthController, respectively.
php artisan make:controller StudentAuthController
php artisan make:controller TeacherAuthController
In the StudentAuthController, let's start by implementing various functionalities. We will include the logic for user registration, login, and logout.
/** Student Register */
public function register(Request $request)
{
$student = Student::create([
'name' => $request->input('name'),
'email' => $request->input('email'),
'password' => $request->input('password'),
]);
$token = $student->createToken('student-token', ['actAsStudent'])->plainTextToken;
return response()->json(['token' => $token, 'student' => $student], 201);
}
/** Student Login */
public function login(Request $request)
{
$student= Student::where('email', $request->input->input('email'))->first();
if (!$student|| !Hash::check($request->input('password'), $student->password)) {
return response()->json(['message' => 'Email or password incorrect'], 401);
}
$token = $student->createToken('student-token', ['actAsStudent'])->plainTextToken;
return response()->json(['token' => $token, 'student' => $student], 200);
}
/** Student Logout*/
public function logout(Request $request)
{
$request->user()->currentAccessToken()->delete();
return response()->json(['message' => 'Logged out successfully'], 200);
}
Similarly, we will replicate the process in the TeacherAuthController.
/** Teacher Register */
public function register(Request $request)
{
$teacher= Teacher::create([
'name' => $request->input('name'),
'email' => $request->input('email'),
'password' => $request->input('password'),
]);
$token = $teacher->createToken('teacher-token', ['actAsTeacher'])->plainTextToken;
return response()->json(['token' => $token, 'teacher' => $teacher], 201);
}
/** Teacher Login */
public function login(Request $request)
{
$teacher = Teacher::where('email', $request->input->input('email'))->first();
if (!$teacher || !Hash::check($request->input('password'), $teacher->password)) {
return response()->json(['message' => 'Email or password incorrect'], 401);
}
$token = $teacher->createToken('teacher-token', ['actAsTeacher'])->plainTextToken;
return response()->json(['token' => $token, 'teacher' => $teacher], 200);
}
/** Teacher Logout*/
public function logout(Request $request)
{
$request->user()->currentAccessToken()->delete();
return response()->json(['message' => 'Logged out successfully'], 200);
}
With our models configured, the next step involves creating middleware to ensure that students cannot access teachers' routes and vice versa.
php artisan make:middleware StudentMiddleware
php artisan make:middleware TeacherMiddleware
In the middleware, our objective is to inspect each incoming request for the "actAsStudent" or "actAsTeacher" ability. If the request lacks these abilities, we will respond with a message indicating that the user is not authorized.
class Student
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
if (!$request->user()->tokenCan('actAsStudent')) {
return response()->json('Not Authorized', 401);
}
return $next($request);
}
}
class Teacher
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
if (!$request->user()->tokenCan('actAsTeacher')) {
return response()->json('Not Authorized', 401);
}
return $next($request);
}
}
We need to include these middlewares in the middlewareAliases
array located in the app/Http/Kernel.php
file.
'student' => \App\Http\Middleware\Student::class,
'teacher' => \App\Http\Middleware\Teacher::class,
Lastly, we should generate and attach these middlewares to our routes. As we are constructing APIs, our routes will be defined in the routes/api.php
file.
/** Student Routes */
Route::controller(StudentAuthController::class)->group(function () {
Route::group(['middleware' => ['auth:sanctum', 'student']], function () {
Route::post('/student/logout', 'logout');
});
Route::post('/student/register', 'register');
Route::post('/student/login', 'login');
});
/** Teacher Routes */
Route::controller(TeacherAuthController::class)->group(function () {
Route::group(['middleware' => ['auth:sanctum', 'teacher']], function () {
Route::post('/teacher/logout', 'logout');
});
Route::post('/teacher/register', 'register');
Route::post('/teacher/login', 'login');
});
Conclusion
In conclusion, implementing a system with multiple authentications using Laravel Sanctum might initially seem complex. However, with the steps outlined in this article, you can efficiently achieve this goal. By setting up models, controllers, and middlewares tailored for different users, you can ensure secure authentication for distinct user roles. With Laravel's flexibility and tools like Sanctum, creating a robust authentication system that differentiates between users and restricts their access becomes a manageable task. This approach enhances the security and functionality of your application, providing a seamless experience for users.
Subscribe to my newsletter
Read articles from David Adigwu directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
David Adigwu
David Adigwu
An explorative and curious individual with an inquisitive mind who is interested in career growth in the tech space. A PHP/Laravel Developer Grounded in backend software engineering which includes, APIs development, debugging, software solutions and consultancy services. Leveraging long term experiences in developing elegant software and proficiency in technologies like Slack, JIRA, GIT, LINUX OS, etc. to contribute positively to the profitability of the organization.