Laravel 8 REST API with Sanctum

Laravel 8 REST API with Sanctum

A beginner's guide from scratch

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!

max-verstappen.webp Max Verstappen - Formula 1 driver

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.

1-headers.png

Register (Post / JSON)

Using data that will not validate

2-registerinvalid.png

Registering with valid data

2-registervalid.png

Logging in with invalid data

4-logininvalid.png

Logging in with valid data

5-loginvalid.png

Who am I? Not being authenticated

6-whoami-notauth.png

Who am I? Authenticated

7-usebearertoken.png

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!