> Manuales > Manual del desarrollo de API con Laravel

Cómo trabajar con Sanctum para el desarrollo de la autenticación de usuarios en API REST con el modelo stateless, en Laravel.

Autenticación con tokens para API usando Sanctum en Laravel

En este artículo vamos a cambiar un poco de tercio, en relación a todo lo que veníamos abordando en el Manual del Desarrollo de APIs con Laravel. Hasta ahora hemos trabajado siempre en el modelo de trabajo basado en sesiones (stateful), pero es solo una de las posibilidades de Laravel Sanctum. La otra posibilidad consiste en el trabajo con tokens de API, especialmente pensado en servicios web que no manejen estado (stateless).

Para explicar todo el flujo de Autenticación con tokens para API usando Sanctum en Laravel seguiremos los siguientes apartados.

Consideraciones Stateful o Stateless

En otras ocasiones ya hemos abordado la diferencia entre estos dos métodos de trabajo para la construcción de APIs. Puedes consultar el primer artículo dedicado a los Packages del ecosistema Laravel para construir un API.

De todos modos cabe decir que el modelo stateful es únicamente adecuado cuando vamos a trabajar con un proyecto SPA que depende directamente del sitio web donde va a ser consumido, ya sea en el mismo dominio o en un subdominio dependiente.

Si ya queremos trabajar con el API desde cualquier dominio posible, o incluso desde otras plataformas que no sean específicamente web, como aplicaciones móviles o aplicaciones de escritorio, lo adecuado es acudir al modelo Stateless. También resultará el modelo adecuado cuando necesitamos altas o muy altas características de escalabilidad, ya que un proyecto backend que trabaja con sesiones resulta más difícil de escalar, llegando a ser casi imposible de gestionar en un cluster de servidores.

Qué son los token de API

En el modelo stateless trabajamos con tokens de API para la autorización de los usuarios. Funcionan básicamente de la siguiente manera:

Se puede ver más información a nivel general sobre este mecanismo de trabajo de token en el artículo siguiente: Autenticación por token.

Por suerte para nosotros Laravel Sanctum gestiona perfectamente el modelo Stateless y nos permite trabajar con tokens de una manera muy sencilla, como vamos a ver a continuación.

Instalamos el proyecto Laravel

Vamos a comenzar desde cero, creando un nuevo proyecto Laravel en el que implementaremos el trabajo con tokens de API.

La manera más sencilla actualmente para crear un nuevo proyecto Laravel es vía Sail, un mecanismo muy práctico para empezar a trabajar sin tener que preocuparse por el entorno y todos los servicios necesarios como las bases de datos.

curl -s "https://laravel.build/mi-proyecto-de-api?with=mariadb,redis,mailpit" | bash

En el comando anterior solamente hemos elegido algunos servicios de los disponibles al usar Sail, porque hay cosas que no las vamos a necesitar. Simplemente sustituyes mi-proyecto-de-api por el nombre de tu proyecto. Puedes seleccionar los servicios que prefieras. Por ejemplo en el comando anterior estamos definiendo que se use MariaDB en lugar de MySQL, pero esto es solo una preferencia personal y puedes cambiarlo si lo deseas.

Luego nos metemos en la carpeta que se ha generado con el proyecto y hacemos:

./vendor/bin/sail up

Pero es preferible crear el shortcut para hacer simplemente:

sail up

Todo el trabajo con contenedores Docker em Laravel, usando Sail, lo encuentras detallado en nuestra Guía de Laravel Sail.

Como Sanctum ya viene instalado en principio solamente hace falta correr las migraciones.

sail artisan migrate

Trait para trabajar con tokens en el modelo User

Para usar tokens para autenticación de usuarios deberíamos usar un trait en el modelo de usuarios (User) que está creado ya.

El trait es Laravel\Sanctum\HasApiTokens. Este trait ya se usa actualmente en el modelo, por lo que no necesitamos realizar cambios. Solamente lo queremos mencionar para que seas consciente de las configuraciones existentes en el proyecto, de casa, que te permitirán usar los tokens para autenticación.

Flujo para el registro de usuarios

Ahora vamos a ver todas las cosas que necesitamos incorporar a nuestra aplicación para poder trabajar con los Token. Todo este trabajo lo tenemos que configurar manualmente, ya que los starter kits que nos ofrecen en Laravel tienen código que está preparado para trabajar exclusivamente con el modelo stateful.

Ruta para el registro de usuarios

Creamos la ruta para permitir el registro de usuarios de nuestro API en el archivo de rutas de API: routes/api.php

Route::post('/auth/register', [RegisterController::class, 'registerUser']);

Controlador para registro de usuarios

Creamos el controlador RegisterController con Artisan.

php artisan make:controller Auth/RegisterController

He creado el controlador de registro dentro de una carpeta llamada Auth. Esto no es necesario pero puede ayudarnos a mantener ordenados y agrupados todos los controladores del proceso de autenticación.

Pero recuerda que si estás en Sail tienes que ejecutar el comando así:

sail artisan make:controller Auth/RegisterController

Esto de la personalización de los comandos para Sail lo damos ya por sabido, por lo que no lo volveré a mencionar en el artículo.

El código completo de este controlador lo podemos ver en el siguiente listado:

<?php

namespace App\Http\Controllers\Auth;

use App\Models\User;
use Illuminate\Http\Request;
use OpenApi\Annotations as OA;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;

class RegisterController extends Controller
{

    private $registerValidationRules = [
        'name' => 'required',
        'email' => 'required|email|unique:users,email',
        'password' => 'required'
    ];

    public function registerUser(Request $request) {
        $validateUser = Validator::make($request->all(), $this->registerValidationRules);
        
        if($validateUser->fails()){
            return response()->json([
                'message' => 'Ha ocurrido un error de validación',
                'errors' => $validateUser->errors()
            ], 400);
        }

        $user = User::create([
            'name' => $request->name,
            'email' => $request->email,
            'password' => Hash::make($request->password)
        ]);

        return response()->json([
            'message' => 'El usuario se ha creado',
            'token' => $user->createToken("API ACCESS TOKEN")->plainTextToken
        ], 200);
    }
}

Flujo para login de usuarios

Ahora vamos a ver cómo se implementaría toda la mecánica de login de usuarios en nuestro API.

Ruta para el login:

Route::post('/auth/login', [LoginController::class, 'loginUser']);

Controlador para login de usuarios en el API

Creamos el controlador LoginController con artisan:

php artisan make:controller Auth/LoginController

El código de este controlador lo encuentras a continuación:

<?php

namespace App\Http\Controllers\Auth;

use App\Models\User;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Validator;

class LoginController extends Controller
{
    private $loginValidationRules = [
        'email' => 'required|email',
        'password' => 'required'
    ];

    public function loginUser(Request $request) {
        $validateUser = Validator::make($request->all(), $this->loginValidationRules);

        if($validateUser->fails()){
            return response()->json([
                'message' => 'Error de validación',
                'errors' => $validateUser->errors()
            ], 401);
        }

        if(!Auth::attempt($request->only(['email', 'password']))){
            return response()->json([
                'message' => 'El email y el password no corresponden con alguno de los usuarios',
            ], 401);
        }

        $user = User::where('email', $request->email)->first();

        return response()->json([
            'message' => 'Login correcto',
            'token' => $user->createToken("API ACCESS TOKEN")->plainTextToken
        ], 200);
    }
}

Middleware 'auth:sanctum'

Otra cosa que nos debe de quedar muy clara es cómo autorizar el acceso a un endpoint solamente si accede un usuario autenticado dentro de la aplicación, verificando el correspondiente token. Esto se puede realizar de diversos modos, siendo el más directo el uso del middleware 'auth:sanctum', que nos permite asegurar que ciertas rutas están solamente estén disponibles para usuarios debidamente autenticados.

Un ejemplo de ruta que usa este middleware lo vamos a usar para el logout.

Flujo para logout de usuarios en el API

Ahora veremos cómo realizar la operativa para cerrar la sesión de los usuarios, que tendrá básicamente que eliminar los Token asociados al usuario que hace el logout.

Ruta para logout

Route::middleware('auth:sanctum')->get('/auth/logout', [LogoutController::class, 'logoutUser']);

Controlador para cerrar la sesión y eliminar el token

Creamos el controlador LogoutController

php artisan make:controller Auth/LogoutController

El código completo del controlador LogoutController se puede ver a continuación.

<?php

namespace App\Http\Controllers\Auth;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;

class LogoutController extends Controller
{
    public function logoutUser() {
        $user = Auth::user();
        $user->tokens()->delete();

        return response()->json([
            'message' => 'Has salido de la cuenta',
        ], 200);
    }
}

Otras operativas para el trabajo con token disponibles en Sanctum

En este artículo hemos visto lo más básico sobre los token para APIs. En realidad Laravel permite trabajar también con otro tipo de operativas esenciales para API con necesidades un poco más avanzadas.

Por ejemplo podemos crear tokens que tengan un tiempo de caducidad más o menos corto, crear tokens que ofrezcan "scopes" determinados, de modo que podamos autorizar o no algunas funcionalidades dependiendo del tipo de token expedido.

En caso de que las necesites te recomendamos leer la documentación de Laravel para encontrar más información sobre las cosas adicionales que puedes llegar a realizar con los token de API gracias a Sanctum.

Miguel Angel Alvarez

Fundador de DesarrolloWeb.com y la plataforma de formación online EscuelaIT. Com...

Manual