Good day, fellow reader.
Today I want to show you how easily you can build an authenticated API using the power of Laravel and Sanctum.
So, buckle up, aaand it's lights out and away we go!
Laravel8 REST API
For this tutorial, you'll only need:
- Basic knowledge of Laravel framework.
- Simple usage of a REST API Client (i.e.: Insomnia , Postman , Hoppscotch)
- Vague idea of what a REST API is.
Don't you know exactly what a REST API is? A deep look into RESTful APIs by Victoria Lo got you covered in few lines
What is Sanctum?
As per the official documentation
Laravel Sanctum provides a featherweight authentication system for SPAs (single page applications), mobile applications, and simple, token based APIs. Sanctum allows each user of your application to generate multiple API tokens for their account. These tokens may be granted abilities / scopes which specify which actions the tokens are allowed to perform.
Preparing the Laravel project
We'll start with a fresh Laravel 8 API project.
composer create-project --prefer-dist laravel/laravel sanctum-api
The good news is, Sanctum is already installed and configured for you in Laravel 8!
You'll only need to setup your local database in .env
file and you're good to go
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=sanctum-api
DB_USERNAME=root
DB_PASSWORD=mysecretpassword
Now, we need to migrate our database data. As you probably know, doing that in Laravel is easy as:
php artisan migrate
Writing the controllers
We are going to use the User
model, that comes with default Laravel. You don't need to add the HasApiTokens
trait to the model, nor configure anything in RouteServiceProvider.php
. This version of Laravel already addressed it for you.
Now, let's create the controller for handling the auth requests.
php artisan make:controller AuthController
Registering via API
In there we will add the register function to handle registration within the Laravel 8 API
public function register(Request $request) {
$validated = $request->validate([
'name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|min:8',
]);
$user = User::create([
'name' => $validated['name'],
'email' => $validated['email'],
'password' => Hash::make($validated['password']),
]);
$token = $user->createToken('auth_token')->plainTextToken;
return response()->json([
'access_token' => $token,
'token_type' => 'Bearer',
]);
}
What's going on here? Well, the first two parts are Laravel's basic way to validate a request and create a User with the validated data.
The juicy stuff Sanctum-wise is here:
$token = $user->createToken('auth_token')->plainTextToken;
We need the plainTextToken
to pass it to the client. This is done by Sanctum. The token would be a string like 6|BNh21lDInxW8Zj00ZMUM7ZaZ9kPxV45yhIA76Tfk
. We return the JSON response with the token_type as Bearer, we can use it to hit the protected Laravel 8 API endpoints right away.
Log in via Laravel 8 API
But, what happens if we forget our token? We should log in to retrieve one, so we need to write a controller function for it.
public function login(Request $request) {
if (!Auth::attempt($request->only('email', 'password'))) {
return response()->json(['message' => 'Incorrect e-mail or password'], 401);
}
$user = User::where('email', $request['email'])->firstOrFail();
$token = $user->createToken('auth_token')->plainTextToken;
return response()->json([
'access_token' => $token,
'token_type' => 'Bearer',
]);
}
As you can see, the last part is identical to the previous, only this time we try to log in the user with the request data, instead of creating a new one.
Protected route handling in API
Finally, we will add a simple controller handle for the endpoint that would return the current user. These will be authenticated users only. You can add that restriction in the controller, but I believe it's cleaner to do it in the routes file.
public function whoami(Request $request) {
return $request->user();
}
Routes for the REST API
The routes for an API shouldn't be in the usual routes\web.php
. We will use the auto-generated routes\api.php
one.
This brings at least two benefits:
- Separated routes from our app to the ones that are API-based.
- Auto-prefixing: The API prefix is automatically inserted in every route we code there.
Route::post('/register', [AuthController::class, 'register']);
Route::post('/login', [AuthController::class, 'login']);
Route::middleware('auth:sanctum')->get('/whoami', [AuthController::class, 'whoami']);
See that middleware in the third route? That means that route will only be accessible by authorized users.
Using the Laravel 8 REST API
We are going to test our application using the php artisan serve
command, which starts a Laravel development server for default at http://127.0.0.1:8000
You can use any REST client, I'm using Insomnia for this guide.
Setting up the headers
Add "Accept: application/json" to the headers so you avoid html responses from Laravel.
Register (Post / JSON)
Using data that will not validate
Registering with valid data
Logging in with invalid data
Logging in with valid data
Who am I? Not being authenticated
Who am I? Authenticated
Full code of Laravel 8 API (additions to default Laravel 8 code)
Summary
This was a simple example, yet, you can extend it for your models, and you'll already have a working token-based authentication in your project. Hope you enjoyed it!
See you around!