Sanctum authentication with roles

Stefan Bogdanescu

Founder & Senior Architect · 2026-06-29

Laravel Company

Mastering Sanctum Authentication with Custom Roles in Laravel

Implementing robust role-based access control (RBAC) alongside token-based authentication like Laravel Sanctum can seem complex, especially when you want to decouple your user roles from the standard users table. It’s a common architectural challenge. As a senior developer, I can assure you that the difficulty often lies not in configuring Sanctum itself, but in correctly structuring the Eloquent relationships and authorization logic around it.

Let's break down why trying to inject custom guards directly into config/auth.php for Sanctum often fails, and outline the proper, scalable way to handle user roles with Sanctum tokens.

The Misconception: Guards vs. Authorization

The confusion often stems from mixing two distinct concepts: Authentication (who you are, handled by Sanctum tokens) and Authorization (what you are allowed to do, handled by roles/permissions).

Laravel's authentication system (config/auth.php) defines how users log in (web sessions, API tokens). While you can define custom guards, Sanctum primarily relies on its own token mechanism tied to the abilities or standard token structure. Roles are typically managed through Eloquent relationships and authorization gates, not by redefining the core authentication guard itself.

The Recommended Architecture: Separate Tables for Scalability

If you need separate tables for users and roles (e.g., an admin table separate from a standard user table), the key is to establish clear, many-to-many relationships via pivot tables. This pattern ensures data integrity and flexibility, which aligns perfectly with Laravel’s object-relational mapping philosophy.

Here is the recommended structure:

  1. Users Table: Stores core user information.
  2. Roles Table: Stores role definitions (e.g., 'admin', 'editor').
  3. Pivot Table (Role-User): Links users to roles, defining their permissions.

Step 1: Database Setup and Models

You would define your models and relationships clearly in your Eloquent structure. For example, using a package like Spatie's Permission is often the fastest route, but if building custom logic, manually setting up pivot tables is essential.

// Example basic setup (assuming you are using separate tables)

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class User extends Authenticatable
{
    // ... standard Sanctum integration here
    public function roles()
    {
        // Relationship to the pivot table linking users and roles
        return $this->belongsToMany(Role::class);
    }
}

class Role extends Model
{
    // ... role details
    public function users()
    {
        return $this->belongsToMany(User::class);
    }
}

Step 2: Integrating Sanctum for API Access

Sanctum's job is to verify the token and identify who sent it. When a request hits your Sanctum middleware, you retrieve the authenticated User model.

Crucially, once the user is authenticated via Sanctum, you use that authenticated ID to check their roles:

// Example API route protection using Sanctum middleware
Route::middleware('auth:sanctum')->get('/admin-dashboard', function (Request $request) {
    $user = $request->user();

    // Authorization Check: Does this user have the 'admin' role?
    if ($user->roles()->where('name', 'admin')->exists()) {
        return response()->json(['message' => 'Welcome, Administrator!'], 200);
    }

    abort(403, 'Unauthorized action.');
});

Conclusion: Decoupling Concerns

Do not try to force Sanctum into a role management system by modifying the core authentication guard. Instead, treat them as separate concerns. Sanctum handles Authentication (Is this token valid? Who is the user?), and your Eloquent structure handles Authorization (What can this authenticated user do?).

By leveraging Eloquent relationships and Laravel's built-in authorization tools (Gates or Policies) alongside Sanctum, you achieve a highly decoupled, scalable system. This approach aligns perfectly with building robust applications on the foundation provided by frameworks like Laravel, allowing you to focus on clean data relationships rather than fighting against internal configuration settings. For more deep dives into architectural patterns in Laravel development, exploring official documentation and community resources is always beneficial.