Kritim Yantra
Jul 15, 2025
Imagine you’ve just finished building an API for your shiny new Laravel 12 app. You’ve got login working, data is flowing... but wait.
Suddenly, your intern logs in and deletes all the user data—because your API doesn’t know the difference between an admin, a manager, or a user.
Ouch.
Enter: Role-Based Access Control (RBAC) with Laravel Sanctum.
In this guide, we’ll walk you through how to build secure, role-specific API access using Laravel 12 and Sanctum. Whether you're working on a personal project or building a real-world application, this tutorial will help you create permission-aware APIs without pulling your hair out.
Laravel Sanctum is a simple package that allows you to authenticate users via API tokens (SPA or mobile apps). It’s lightweight, easy to implement, and perfect for most Laravel apps.
Unlike Passport, which is OAuth2-heavy, Sanctum keeps it simple—making it beginner-friendly and lightning-fast to set up.
RBAC means giving users different roles, and limiting what each role can do.
Think of it like access badges at a company:
With RBAC, your API checks who’s calling and what they’re allowed to do before serving data.
Let’s build a simple API where users can log in and get different data based on their roles.
Install Laravel Sanctum via Composer:
composer require laravel/sanctum
Publish the Sanctum config and run migrations:
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
php artisan migrate
In your User.php
model, add the HasApiTokens trait:
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
}
Let’s give each user a role.
php artisan make:migration add_role_to_users_table
In the migration file:
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->string('role')->default('user');
});
}
Then run:
php artisan migrate
Now, users can have roles like admin
, manager
, or user
.
Let’s create an auth controller for register and login.
php artisan make:controller AuthController
In AuthController.php
:
public function register(Request $request)
{
$user = User::create([
'name' => $request->name,
'email' => $request->email,
'password' => bcrypt($request->password),
'role' => $request->role ?? 'user',
]);
$token = $user->createToken('api-token')->plainTextToken;
return response()->json(['token' => $token], 201);
}
public function login(Request $request)
{
$user = User::where('email', $request->email)->first();
if (! $user || ! Hash::check($request->password, $user->password)) {
return response()->json(['message' => 'Invalid credentials'], 401);
}
$token = $user->createToken('api-token')->plainTextToken;
return response()->json(['token' => $token]);
}
php artisan make:middleware RoleMiddleware
In app/Http/Middleware/RoleMiddleware.php
:
public function handle($request, Closure $next, $role)
{
if ($request->user()->role !== $role) {
return response()->json(['message' => 'Unauthorized'], 403);
}
return $next($request);
}
Register it in bootstrap/app.php
:
->withMiddleware(function ($middleware) {
$middleware->alias([
'role' => \App\Http\Middleware\RoleMiddleware::class,
]);
})
In routes/api.php
:
// Public route
Route::post('/register', [AuthController::class, 'register']);
Route::post('/login', [AuthController::class, 'login']);
// Protected route for admins
Route::middleware(['auth:sanctum', 'role:admin'])->get('/admin', function () {
return response()->json(['message' => 'Welcome, Admin!']);
});
// Protected route for managers
Route::middleware(['auth:sanctum', 'role:manager'])->get('/manager', function () {
return response()->json(['message' => 'Manager dashboard']);
});
// For all authenticated users
Route::middleware(['auth:sanctum'])->get('/profile', function (Request $request) {
return $request->user();
});
🔥 Now, if a user with the user
role tries to access /admin
, they’ll get blocked with a 403 Forbidden.
Imagine an e-commerce app:
Using Sanctum and middleware, you can enforce this easily. That means no more “oops” moments where the wrong user accesses sensitive endpoints.
🟡 Forgetting to protect routes: Always use middleware on your sensitive routes.
🔐 Not hashing passwords: Use bcrypt()
when registering users.
❌ Hardcoding roles: You can improve this by moving to a roles table and many-to-many relationships later.
hasRole()
helper in the User model for cleaner codepublic function hasRole($role)
{
return $this->role === $role;
}
By now, you should be able to:
Try building a simple blog API with:
Use the same pattern you learned today—and watch your Laravel skills level up 🚀
Not with this basic setup. But you can extend it using a roles
table and many-to-many relationships.
For simple token-based APIs—yes. Sanctum is easier and lighter.
Absolutely! Just make sure to secure your tokens, use HTTPS, and follow best practices.
Which part of role-based access did you find most useful or confusing?
Drop your questions and thoughts in the comments below—I’m here to help! 👇
No comments yet. Be the first to comment!
Please log in to post a comment:
Sign in with Google