Hello! Welcome to your next lesson in the "Authentication & Authorization" module.
In our previous lesson, we built a complete session-based authentication system using Laravel Breeze. This approach is perfect for traditional, stateful web applications where the server and browser maintain a persistent session. However, modern development often involves "stateless" clients like mobile apps or JavaScript Single Page Applications (SPAs) that communicate with a backend via an API. These clients can't rely on web sessions and cookies in the same way.
This lesson addresses that exact scenario. We'll explore how to implement a secure, token-based authentication system for a stateless API. Our tool for this will be Laravel Sanctum, a lightweight and powerful package designed for this purpose. Your goal is to build and understand the full authentication lifecycle for an API: registering a user, logging in to receive a token, using that token to access protected data, and logging out by revoking the token.
1. From Stateful Sessions to Stateless Tokens
Before diving in, let's clarify the conceptual shift from our last lesson. In a session-based system, the server creates a session for a user upon login and stores its ID in a cookie. For every subsequent request, the browser sends the cookie, and the server uses it to retrieve the user's session data. The server "remembers" the user.
In a stateless API, the server remembers nothing about previous requests. Each request must contain all the information needed to process it, including authentication credentials. This is where tokens come in.

Let's get a formal introduction to Laravel Sanctum and its role in this process.
Laravel Sanctum - Laravel 12.x
The official Laravel documentation provides the best starting point. It explains what Sanctum is and the problems it solves.
Read the 'Introduction' section, focusing on the 'How it Works' part for 'API Tokens'. Note how it describes Sanctum as a simpler alternative to OAuth for issuing 'personal access tokens'.
As the documentation states, Sanctum is designed for first-party applications where you control both the frontend and backend. It's much simpler than a full OAuth2 implementation like Laravel Passport, making it the perfect choice for most API projects.
2. Setting Up Laravel Sanctum
Just like with Breeze, our first step is to install and configure the package. This involves pulling it in with Composer, publishing its assets, and running a migration.
Laravel API Crash Course With Sanctum | Laravel Sanctum Full Tutorial | How to Build Laravel API
This video from 'Code With Dary' provides a clear, step-by-step guide to installing Sanctum and setting up the database. We will follow these initial steps.
Watch from 02:54 to 07:06. Follow along in your own Laravel project. The key steps are summarized below.
Here's a summary of the commands and steps from the video to execute in your project terminal:
-
Install Sanctum via Composer:
composer require laravel/sanctum -
Publish Configuration and Migrations: This command copies Sanctum's configuration file (
config/sanctum.php) and its migration file to your application.php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider" -
Run Migrations: This will create the
personal_access_tokenstable in your database, which Sanctum uses to store the generated tokens. Remember to have your.envfile configured for your MSSQL database.php artisan migrate -
Update the User Model: Finally, you need to add the
HasApiTokenstrait to yourUsermodel. This trait provides the methods we'll use to create and manage tokens (e.g.,createToken,tokens).Open
app/Models/User.phpand add the trait:<?php namespace App\Models; // ... other use statements use Laravel\Sanctum\HasApiTokens; // <-- Import the trait class User extends Authenticatable { use HasApiTokens, HasFactory, Notifiable; // <-- Use the trait // ... rest of the model }
With these steps, Sanctum is installed and ready to use.
3. Building the Authentication Endpoints
Now for the core logic. We'll create an AuthController to handle registration, login, and logout. All our routes will live in routes/api.php.
First, create the controller:
php artisan make:controller Auth/AuthController
The Registration Flow
Our register endpoint will validate the user's details, create a new user account, and immediately issue an API token.
Laravel API Crash Course With Sanctum | Laravel Sanctum Full Tutorial | How to Build Laravel API
Let's implement the registration logic. This video segment covers creating a Form Request for validation, creating the user, and most importantly, generating the first API token.
Watch from 25:11 to 30:37. Pay close attention to the use of $user->createToken(...) and the retrieval of the $token->plainTextToken. This is the token your API client will need to store.
Here is a summary of the routes and controller logic you'll build.
Define the Route in routes/api.php:
use App\Http\Controllers\Auth\AuthController;
Route::post('/register', [AuthController::class, 'register']);
Implement the register method in app/Http/Controllers/Auth/AuthController.php:
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\Rules;
class AuthController extends Controller
{
public function register(Request $request)
{
$request->validate([
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
'password' => ['required', 'confirmed', Rules\Password::defaults()],
]);
$user = User::create([
'name' => $request->name,
'email' => $request->email,
'password' => Hash::make($request->password),
]);
$token = $user->createToken('api-token-of-'.$user->name)->plainTextToken;
return response()->json([
'user' => $user,
'token' => $token,
], 201);
}
}
Key points:
- The
createToken()method generates a new token for the user. The string argument is just a descriptive name for the token. - The token is hashed before being stored in the database. You can only see the plain text version once, right after creation, using the
plainTextTokenproperty. This is what you must return to the client.
The Login Flow
The login endpoint will verify a user's credentials and, if correct, issue a new token for them to use.
Laravel API Crash Course With Sanctum | Laravel Sanctum Full Tutorial | How to Build Laravel API
Now for the login endpoint. This part is crucial as it involves validating existing credentials and handling both success and failure cases.
Watch from 34:01 to 40:10. Notice how the logic first attempts to authenticate the user and returns a 401 Unauthorized error if it fails. If successful, it generates and returns a new token.
Define the Route in routes/api.php:
// Add this route alongside your register route
Route::post('/login', [AuthController::class, 'login']);
Implement the login method in app/Http/Controllers/Auth/AuthController.php:
use Illuminate\Validation\ValidationException;
// ... inside AuthController
public function login(Request $request)
{
$request->validate([
'email' => ['required', 'email'],
'password' => ['required'],
]);
$user = User::where('email', $request->email)->first();
if (! $user || ! Hash::check($request->password, $user->password)) {
throw ValidationException::withMessages([
'email' => ['The provided credentials are incorrect.'],
]);
}
$token = $user->createToken('api-token-of-'.$user->name)->plainTextToken;
return response()->json([
'user' => $user,
'token' => $token,
]);
}
4. Protecting Routes and Authenticating Requests
With login and registration working, we now have a way to get tokens. The next step is to protect certain API endpoints so that only authenticated users can access them.
This is done using the auth:sanctum middleware. Any route or group of routes protected by this middleware will require a valid Sanctum token in the request header.
Laravel API Crash Course With Sanctum | Laravel Sanctum Full Tutorial | How to Build Laravel API
Let's see how to protect our routes and how a client application would use the token. This video demonstrates using Postman to simulate an API client.
This is a key practical section. Watch from 10:55 to 14:14 to see how to set up Postman, then watch from 40:10 to 45:49. Focus on: Creating a route group with the auth:sanctum middleware. Placing a protected route inside the group. Making a request with the Authorization: Bearer <token> header in Postman to access the protected route.
Update routes/api.php to protect routes:
// Public routes
Route::post('/register', [AuthController::class, 'register']);
Route::post('/login', [AuthController::class, 'login']);
// Protected routes
Route::middleware('auth:sanctum')->group(function () {
// This route returns the currently authenticated user
Route::get('/user', function (Request $request) {
return $request->user();
});
// We will add the logout route here later
});
To test this:
- Use an API client like Postman to hit your
/api/loginendpoint with correct credentials. - Copy the
tokenvalue from the JSON response. - Create a new request to
/api/user. - In the "Authorization" tab, select "Bearer Token" and paste the token you copied.
- Send the request. You should receive the authenticated user's data with a
200 OKstatus. If you try without the token, you'll get a401 Unauthorizederror.
5. Implementing Logout by Revoking Tokens
A user logging out should invalidate their token so it can no longer be used. This is a server-side action.
Laravel API Crash Course With Sanctum | Laravel Sanctum Full Tutorial | How to Build Laravel API
Finally, let's implement a secure logout. This involves more than just deleting the token on the client; we need to revoke it in our database.
Watch from 01:14:18 to 01:17:32. The key line of code is $request->user()->currentAccessToken()->delete(). Understand that this deletes the specific token that was used to make the logout request.
Define the logout route within the protected group in routes/api.php:
Route::middleware('auth:sanctum')->group(function () {
Route::get('/user', function (Request $request) {
return $request->user();
});
// Add the logout route here
Route::post('/logout', [AuthController::class, 'logout']);
});
Implement the logout method in app/Http/Controllers/Auth/AuthController.php:
// ... inside AuthController
public function logout(Request $request)
{
// Revoke the token that was used to authenticate the current request...
$request->user()->currentAccessToken()->delete();
return response()->json([
'message' => 'Successfully logged out'
]);
}
Now, if you make a POST request to /api/logout with a valid Bearer token, you will get a success message. If you try to use that same token again to access /api/user, it will fail with a 401 Unauthorized error because the token no longer exists in the personal_access_tokens table.
Conclusion
Congratulations! You have successfully implemented a complete token-based authentication system for a stateless API using Laravel Sanctum. You now have the tools to secure APIs for mobile applications, JavaScript frontends, or any other service that needs to communicate with your Laravel backend.
Key Takeaways:
- Stateless APIs require authentication information (like a token) to be sent with every request.
- Laravel Sanctum provides a lightweight and simple way to issue and manage API tokens for first-party applications.
- The
HasApiTokenstrait adds token management capabilities to yourUsermodel. - Tokens are generated via
$user->createToken()and the plain text version is only available once upon creation. - The
auth:sanctummiddleware is used to protect routes, requiring a validBearertoken in theAuthorizationheader. - Secure logout is achieved by revoking the token on the server-side using
$request->user()->currentAccessToken()->delete().
Up Next:
So far, our authentication system can answer the question: "Who is this user?". Now, we need to start answering the next logical question: "What is this user allowed to do?".
In the next lesson, we will dive into Authorization by defining access rules for different users using Gates. This will allow us to create fine-grained permission logic within our application.