Back to Course |
How to Build Laravel 11 API From Scratch

Authentication with Laravel Sanctum and API Tokens

This lesson will look at Laravel API authentication with Laravel Sanctum and API tokens. To understand how it is used and in what situations, you should read the official documentation.

From the docs:

This feature is inspired by GitHub and other applications which issue "personal access tokens".

Every user of your system would have a personal access token, which they would pass when making API calls.


After creating a new Laravel project and running the migrations, we have a personal_access_tokens table.

Next, you need to create a token for the user in your application. It could be some action panel on your page, some action on login, or automatically done after registration.

But, to create a token, the HasApiTokens trait has to be added in a User Model. It should be done after the install:api artisan command was executed.

app/Models/User.php:

use Laravel\Sanctum\HasApiTokens;
 
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
use HasApiTokens;
 
// ...
}

Next, you must protect API routes using the auth:sanctum Middleware. It's the same Middleware we used in the previous lesson for the SPA applications.

routes/api.php:

Route::get('/user', function (Request $request) {
return $request->user();
})->middleware('auth:sanctum');
 
Route::apiResource('categories', \App\Http\Controllers\Api\CategoryController::class)
->middleware('auth:sanctum');
 
Route::get('products', [\App\Http\Controllers\Api\ProductController::class, 'index']);

Now, if we try to access categories without passing any token, we will receive an Unauthenticated message with a 401 Unauthorized status code.

Let's try to create a token for a user using tinker.

If you don't have any users, create one.

Now, let's create a token by passing some name.

The token is in the plainTextToken, which needs to be passed for every API call. In the client, add the created token as a Bearer token. Now, we can see the list of the categories from the API.

In the database, we have an encoded token.

If you want to delete all the tokens, you can do that.


Finally, when using tokens, you can pass abilities, better known as permissions. When creating a token, the second parameter is the array of abilities.

Let's create a token that can view all categories but not a specific category.

In the Controller, we need to check if the user has access. The check is done on the authenticated user Model using the tokenCan method.

app/Http/Controllers/Api/CategoryController.php:

class CategoryController extends Controller
{
public function index()
{
abort_if(! auth()->user()->tokenCan('categories-list'), 403);
 
return CategoryResource::collection(Category::all());
}
 
public function show(Category $category)
{
abort_if(! auth()->user()->tokenCan('categories-show'), 403);
 
return new CategoryResource($category);
}
 
// ...
}

With the new token, we can see a list of the categories.

But, when we try to view a single existing category, we get a 403 forbidden status.

This token check can also be done using Middleware, Policies, or your other preferred way.