Configure Laravel Sanctum for SPA authentication and API Tokens

- 👤 Andrés Cruz

🇪🇸 En español

Configure Laravel Sanctum for SPA authentication and API Tokens

Laravel Sanctum is a package for authenticating single-page applications (SPAs) and mobile applications that we can use to protect the Rest API through required authentication; Laravel Sanctum and simple token-based APIs; remember that it is not as direct as adding a session, and this is because a Rest API is recommended to be stateless and this is where Laravel Sanctum comes into play. It allows each user of your application to generate multiple API tokens for their account. Laravel Sanctum provides a lightweight authentication system for SPAs and simple APIs.

Laravel Sanctum is wonderful for when we want to protect a Rest API created with Laravel either through tokens or a hybrid between sessions and cookies; before showing you how to perform the most traditional implementation, let's dive a bit into the subject and introduce what Sanctum is.

Using Laravel Sanctum we ensure that only authenticated users can access the routes that require it.

The idea behind Sanctum is to protect Laravel application APIs through authentication and access tokens. By doing so, it ensures that only authenticated and authorized requests are allowed, which in turn ensures the integrity of the application and the data involved. I hope this has helped you understand a bit more about the theory behind Laravel Sanctum.

Laravel Sanctum offers us two schemes to work with.

What is Laravel Sanctum?

Laravel Sanctum is an authentication package for Laravel that provides a simple and secure method for authenticating single-page applications (SPAs) using users and protecting your API via API tokens. Sanctum allows generating and managing API tokens, which are issued through a rest resource that we implement and passed to the client so that when they want to access protected resources, they must use said access token to connect to the resource and consume the API response.

These tokens are great because you can use them to authenticate API requests and also to restrict access to routes, since, with the token, from Laravel you know which user is trying to consume a specific resource and perform some trace or limitation.

1 SPA Authentication

This is useful when we have an SPA page and you want to add authentication to protect a Rest API and access the user; this option is based on a scheme between session authentication and cookies that we have to configure; it is worth saying that it is the simplest of the two:

At the kernel level, we have to enable the cookie and session service for Sanctum:

//App/Http/Kernel
 
//***
class Kernel extends HttpKernel
{
    //***
 
        'api' => [      \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
            'throttle:api',
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],
    ];

Specify the domain you are going to use for cookie-based authentication in the config/sanctum.php file:

  'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
        '%s%s',
        'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1,laraprimerospasos.test',
        env('APP_URL') ? ','.parse_url(env('APP_URL'), PHP_URL_HOST) : ''
    ))),

If you are using Mac or Linux with Sail, there is no need to modify this file since localhost is present; also, you can place your production domain URL.

In the config/cors.php file you have to enable supports_credentials as true.

To be able to use axios (which we will do later), you must look for the resources/js/bootstrap.js file and place:

axios.defaults.withCredentials = true;

This is to enable the use of cookies with user credentials, and to be able to use it transparently with axios.

Finally, with this, we can use the middleware for route authentication; as an example, we will protect a set of routes:

Route::group(['middleware' => 'auth:sanctum'], function () {
    Route::resource('category', CategoryController::class)->except(["create", "edit"]);
    Route::resource('post', PostController::class)->except(["create", "edit"]);
});

Otherwise, all you have to do is log in and we are ready; you can use this scheme with axios.

2 Based on API Tokens

The next scheme is more manual and in the end is a token-based authentication; for this, now when authenticating, we generate the authentication tokens:

Before starting, we are going to disable the previous Sanctum scheme for SPA authentication:

'api' => [
  //\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
  ***
],

Generate access tokens

Laravel Sanctum provides us with a simple mechanism to add authentication to Rest APIs, through Authentication Tokens or by authentication tokens; in this first entry, we will see how to use the authentication token mechanism which would be the more traditional scheme.

It is worth mentioning that it is not necessary to install Sanctum since, for a long time, Sanctum has been part of a project in Laravel.

In our rest controller, to handle the user, in the case of our Laravel course, it would be the following:

app\Http\Controllers\Api\UserController.php

We will create a login function, using the attempt function with which we can check user credentials provided in the request:

$credentials = [ 'email' => $request->email, 'password' => $request->password ];

Once the credentials have been verified, we create the token and return the response:

Auth::user()->createToken('myapptoken')->plainTextToken;

Finally, the complete code:

public function login(Request $request)
{
    $credentials = [
        'email' => $request->email,
        'password' => $request->password
    ];
    if (Auth::attempt($credentials)) {
        $token = Auth::user()->createToken('myapptoken')->plainTextToken;
     session()->put('token', $token);
        return response()->json($token);
    }
    return response()->json("Usuario y/o contraseña inválido", 422);
}

The most important thing to note is that, although Sanctum provides all the mechanisms to generate the token, it is up to the user to implement the necessary logic to generate the token.

To create tokens for our users, we are going to create a login function that allows generating these tokens (you could also use this function in SPA authentication but without generating the token):

$ php artisan make:controller Api/UserController

In which we will define the following content:

<?php
 
namespace App\Http\Controllers\Api;
 
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
 
class UserController extends Controller
{
    public function login(Request $request)
    {
        $credentials = [
            'email' => $request->email,
            'password' => $request->password
        ];
 
        if(Auth::attempt($credentials)){
            $token = Auth::user()->createToken('myapptoken')->plainTextToken;
 
            return response()->json($token);
        }
        return response()->json("Usuario y/o contraseña inválido");
    }
}

Important to note that Sanctum already comes installed in modern Laravel projects.

More examples with Sanctum

Here are some other examples with authentication in Laravel Sanctum and route protection.

In case the project no longer has Sanctum, you must install Laravel Sanctum using Composer:

$ composer require laravel/sanctum

Then, you will publish the Sanctum configuration and migration files:

$ php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
$ php artisan migrate

Next, we can already protect our routes; for this, we use an authentication middleware in your routes file. For example:

routes/api.php

Route::middleware('auth:sanctum')->group(function () {
   Route::get('/post', function () {
       return view('dashboard');
   });
});

In this example, the "/post" route will only be accessible if the user is authenticated via the Sanctum middleware.

After that, you can generate an API token for an authenticated user. For example:

$token = $user->createToken('token-name')->plainTextToken;

This code will generate an API token for the given user with the name "token-name". Then, you can use the token to authenticate API requests; here is another example of login with Sanctum:

routes/api.php

use App\\Models\\User;
use Illuminate\\Http\\Request;
use Illuminate\\Support\\Facades\\Hash;

Route::post('/login', function (Request $request) {
    $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($request->device_name)->plainTextToken;

    return ['token' => $token];
});

That is just a basic example of how you can use Laravel Sanctum in your Laravel project. I hope it has been useful to you. If you have more questions, feel free to ask.

I agree to receive announcements of interest about this Blog.

We're going to learn about Laravel Sanctum and configure Laravel Sanctum via SPA or API Tokens to secure a REST API with required authentication.

| 👤 Andrés Cruz

🇪🇸 En español