book cover front cover for API Development with Laravel by Akintoye Adegoke

🚀 It’s here!
After months of writing and testing real-world code examples, I’m excited to announce my new book — API Development with Laravel: A Quick Start Guide 🎉
This project-based book introduces you to Laravel, even if you’re completely new to it — and shows you how to build a real Payment Processor API step by step.

🧠 Understanding Token Abilities and Token Ability Checks in Laravel Sanctum

Laravel Sanctum allows your application to issue API tokens for authentication.
Each token can have a set of abilities, which act like permissions — they define what that token is allowed to do.

Let’s explore what token abilities are, how they work, who defines them, and how you can use them to protect routes and control access.


🧩 1. What Are Token Abilities?

A token ability is a label (or tag) that specifies what actions a particular API token can perform.

Think of an ability like a key’s access level — it tells the system what doors the key (token) can open.

🔍 Example Concept

Token NameAbilitiesMeaning (defined by you)
admin-token["view-users", "delete-users"]Can view and delete users
cashier-token["process-payments"]Can process payments only
read-only-token["view-data"]Can only read information

🧠 2. Who Determines What Abilities Mean?

This is crucial to understand:
Laravel does not come with any built-in abilities or predefined meanings.

Instead:

🔑 You, the developer, define both the names and the meanings of the abilities.

Laravel only provides:

  • A way to store abilities on tokens.

  • A way to check if a token includes a given ability.

It does not know what "admin-token" or "cashier-token" means — those are just labels you invent.


🧩 Analogy

Imagine each API token as a keycard and each ability as a label printed on it:

KeycardLabels (Abilities)
Staff Card“cafeteria-access”, “office-entry”
Manager Card“cafeteria-access”, “office-entry”, “server-room-access”

When someone tries to open the server room, the system just checks:

“Does this keycard have the ‘server-room-access’ label?”

It doesn’t know what a “server room” is — you defined that meaning.


⚙️ 3. Creating Tokens With Abilities

When you issue a token, you can attach specific abilities to it.

 
// Example: In your AuthController
$user = User::find(1);

// Create a token that can only view and update profile data
$token = $user->createToken('profile-token', ['view-profile', 'update-profile']);

// Return the token string to the client
return ['token' => $token->plainTextToken];

🧠 Line-by-Line Explanation

CodeExplanation
$user = User::find(1);Get a user model instance.
$user->createToken('profile-token', [...])Create a new personal access token named 'profile-token'.
['view-profile', 'update-profile']These are labels representing abilities — you define what they represent.
$token->plainTextTokenThe actual token string to be used in API requests.

Laravel stores these abilities in the database with the token — it doesn’t interpret them.


🔒 4. Checking Abilities in Code (Manual Checking)

To verify that a token has a particular ability before allowing an action to be performed, use the tokenCan() method.

 
use Illuminate\Http\Request;

public function updateProfile(Request $request)
{
    if (! $request->user()->tokenCan('update-profile')) {
        abort(403, 'Unauthorized action.');
    }

    // Perform profile update logic...
}

🧠 What’s Happening Here

LineMeaning
$request->user()Gets the authenticated user.
tokenCan('update-profile')Checks if the token used for authentication has the "update-profile" label.
abort(403, 'Unauthorized action.')If the token doesn’t have the ability, return an HTTP 403 Forbidden error.

Laravel simply checks if the string 'update-profile' exists among the token’s stored abilities — nothing more.


🚦 5. Protecting Routes Automatically with Middleware

Manual checks work fine for individual methods, but for groups of routes, Laravel Sanctum provides two convenient middleware:

MiddlewareBehavior
abilitiesRequires the token to have all listed abilities
abilityRequires the token to have at least one of the listed abilities

🛠 Step 1: Register the Middleware

Laravel 10 and earlier → add to app/Http/Kernel.php

 
use Laravel\Sanctum\Http\Middleware\CheckAbilities;
use Laravel\Sanctum\Http\Middleware\CheckForAnyAbility;

protected $routeMiddleware = [
    // other middleware...
    'abilities' => CheckAbilities::class,
    'ability' => CheckForAnyAbility::class,
];

Laravel 11 and later → add to bootstrap/app.php

 
use Laravel\Sanctum\Http\Middleware\CheckAbilities;
use Laravel\Sanctum\Http\Middleware\CheckForAnyAbility;
use Illuminate\Foundation\Configuration\Middleware;

$app->withMiddleware(function (Middleware $middleware) {
    $middleware->alias([
        'abilities' => CheckAbilities::class,
        'ability' => CheckForAnyAbility::class,
    ]);
});

This step “teaches” Laravel to recognize the middleware names abilities and ability.


🛠 Step 2: Apply Middleware to Routes

 
use App\Http\Controllers\TransactionController;
use App\Http\Controllers\WalletController;
use Illuminate\Support\Facades\Route;

Route::middleware(['auth:sanctum', 'abilities:secret'])->group(function () {
    Route::post('/wallet/withdraw', [WalletController::class, 'withdrawFund']);
    Route::post('/payment/initiate', [TransactionController::class, 'initTransaction']);
    Route::get('/transaction/verify/{id}', [TransactionController::class, 'verifyTransaction']);
});

🧠 Explanation

CodeMeaning
auth:sanctumEnsures the request uses a valid Sanctum token.
abilities:secretEnsures the token includes the "secret" ability.
Grouping routesAll routes inside share the same restriction automatically.

Laravel doesn’t interpret "secret" — it simply checks if the token has that label.


Example Using ability (any one of them)

 
Route::middleware(['auth:sanctum', 'ability:view-transactions,verify-transactions'])->group(function () {
    Route::get('/transaction/{id}', [TransactionController::class, 'getTransaction']);
});

This route will be accessible to any token that has either "view-transactions" or "verify-transactions".


🧾 6. Full Example Flow

Step 1 — Create Tokens for Different Roles

 
// Admin user
$adminToken = $user->createToken('admin', ['manage-users', 'process-payments']);

// Customer user
$userToken = $user->createToken('customer', ['view-transactions']);

Step 2 — Protect Routes

 
Route::middleware(['auth:sanctum', 'abilities:process-payments'])->group(function () {
    Route::post('/payments', [PaymentController::class, 'process']);
});

✅ The admin token (has process-payments) → can access
❌ The customer token (no process-payments) → gets 403 Unauthorized


⚡ 7. Why Token Abilities Matter

ReasonBenefit
Granular access controlYou can allow or block tokens per feature.
SecurityIf a token is compromised, its actions are limited.
ScalabilityEasy to add or change permissions later.
Best practiceFollows the “principle of least privilege” (give only what’s needed).

✅ Summary

ConceptDescription
Token AbilitiesLabels (strings) that define what a token can do — chosen by you.
Who defines abilities?You do — Laravel doesn’t interpret or enforce their meaning.
tokenCan()Checks if a token has a specific ability (used in controllers).
abilities: middlewareRequires a token to have all listed abilities.
ability: middlewareRequires a token to have at least one listed ability.
PurposeRestrict what tokens can do, improving security and flexibility.

🔐 In One Sentence

Laravel Sanctum token abilities are developer-defined permission tags attached to tokens, checked by Laravel using simple string comparison to decide what each token is allowed to do.

Comments