Ir al contenido principal

Laravel Sanctum: autenticación de una API

 ¿Cómo se implementa autenticación en una API de Laravel?


Implementar autenticación en una API de Laravel es un paso fundamental para asegurar tus endpoints. Laravel ofrece varias opciones, pero la más moderna y recomendada para la mayoría de las API (especialmente las que son consumidas por Single Page Applications o aplicaciones móviles) es Laravel Sanctum.

Vamos a centrarnos en Laravel Sanctum como la solución principal, y luego mencionaremos brevemente otras alternativas.


Autenticación de API con Laravel Sanctum (Recomendado)

Laravel Sanctum es un paquete ligero que ofrece un sistema simple de autenticación basado en tokens para APIs. Es ideal para:

  1. SPAs (Single Page Applications): Donde tu frontend de JavaScript (React, Vue, Angular) y tu API de Laravel están en el mismo dominio o dominios relacionados. Aquí, Sanctum utiliza cookies/sesiones (con protección CSRF) para autenticar al usuario.
  2. Aplicaciones Móviles o Third-Party: Donde no puedes usar cookies. Para estos casos, Sanctum permite generar tokens de API que se envían en el encabezado Authorization.

Conceptos Clave de Sanctum:

  • Tokens de API: Son strings alfanuméricos largos y seguros que los usuarios pueden generar (o que se generan para ellos). Cada token está asociado a un usuario y puede tener "habilidades" (abilities/scopes) específicas que definen qué acciones puede realizar.
  • Trait HasApiTokens: Se añade a tu modelo User para que pueda generar y gestionar tokens.
  • Middleware auth:sanctum: Es el middleware de protección que usas en tus rutas de API.
  • SPA Authentication (Autenticación para SPAs): Si tu SPA y tu API están en el mismo dominio, Sanctum usa un proceso de "cookie-based authentication" que es similar a una sesión web tradicional, pero optimizado para SPAs. Implica el intercambio de un token CSRF al inicio de la sesión.

Implementación Paso a Paso de Laravel Sanctum:

1. Instalación de Sanctum

Abre tu terminal en la raíz de tu proyecto Laravel y ejecuta:

Bash
composer require laravel/sanctum

2. Publicar Migraciones y Ejecutar

Sanctum necesita una tabla en la base de datos para almacenar los tokens de API.

Bash
php artisan vendor:publish --tag="sanctum-migrations"
php artisan migrate

Esto creará una tabla personal_access_tokens en tu base de datos.

Alternativamente, Este paso se puede realizar con 

Bash

php artisan install:api

3. Configuración del Modelo User

Abre tu modelo app/Models/User.php y añade el trait HasApiTokens:

PHP
<?php

namespace App\Models;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens; // <--- Añade esta línea

class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable; // <--- Añade HasApiTokens aquí

    // ... el resto de tu modelo
}

4. Proteger Rutas de API

Para proteger tus rutas de API, usa el middleware auth:sanctum. Generalmente, esto se hace en tu archivo routes/api.php:

PHP
<?php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;

// Rutas públicas o de autenticación (login, registro)
Route::post('/register', [App\Http\Controllers\Auth\RegisterController::class, 'register']);
Route::post('/login', [App\Http\Controllers\Auth\LoginController::class, 'login']);

// Rutas protegidas por Sanctum
Route::middleware('auth:sanctum')->group(function () {
    Route::get('/user', function (Request $request) {
        return $request->user();
    });

    Route::post('/logout', [App\Http\Controllers\Auth\LoginController::class, 'logout']);

    // Ejemplo de ruta con habilidades/scopes
    Route::get('/orders', function (Request $request) {
        // El token debe tener la habilidad 'read:orders'
        if ($request->user()->tokenCan('read:orders')) {
            return response()->json(['message' => 'Lista de órdenes']);
        }
        return response()->json(['message' => 'No tienes permiso para leer órdenes'], 403);
    });
});

5. Implementar Lógica de Autenticación (Login/Logout)

Necesitarás controladores para manejar el registro y el login. Aquí un ejemplo simplificado de un controlador de Login:

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\ValidationException;

class LoginController extends Controller
{
    public function login(Request $request)
    {
        $request->validate([
            'email' => ['required', 'email'],
            'password' => ['required'],
            'device_name' => ['required'], // Necesario para la autenticación de tokens
        ]);

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

        if (! $user || ! Hash::check($request->password, $user->password)) {
            throw ValidationException::withMessages([
                'email' => ['Las credenciales proporcionadas son incorrectas.'],
            ]);
        }

        // Si el login es exitoso, crea un token
        // Puedes definir habilidades (scopes) aquí
        $token = $user->createToken($request->device_name, ['read', 'write:orders'])->plainTextToken;

        return response()->json(['token' => $token]);
    }

    public function logout(Request $request)
    {
        // Revocar el token actual usado para la autenticación
        $request->user()->currentAccessToken()->delete();

        return response()->json(['message' => 'Sesión cerrada exitosamente']);
    }
}

6. Cómo usar el Token en el Cliente (Móvil/Third-Party)

Una vez que el cliente obtiene el token (después de un login exitoso), debe enviarlo en el encabezado Authorization de todas las solicitudes subsiguientes a rutas protegidas.

Authorization: Bearer YOUR_GENERATED_TOKEN_HERE

Ejemplo con JavaScript (fetch API):

JavaScript
// Después de iniciar sesión y obtener el token
const token = 'tu_token_generado_aqui';

fetch('http://localhost:8000/api/user', {
    method: 'GET',
    headers: {
        'Accept': 'application/json',
        'Authorization': `Bearer ${token}` // Envía el token Bearer
    }
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));

7. Configuración para SPAs (Autenticación basada en Cookies)

Si tu SPA y tu API están en el mismo dominio (o subdominio), puedes usar la autenticación basada en cookies.

  1. Añade el middleware EnsureFrontendRequestsAreStateful:

    Abre app/Http/Kernel.php y asegúrate de que el middleware \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class esté en el grupo de middleware api o web. (Generalmente ya está en web por defecto).

  2. Configura tus dominios frontend en config/sanctum.php:

    Asegúrate de que el dominio de tu SPA esté listado en la propiedad stateful del archivo config/sanctum.php.

    PHP
    // config/sanctum.php
    'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', 'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1')),
    

    También configura CORS en config/cors.php.

  3. Llama al endpoint sanctum/csrf-cookie:

    Desde tu SPA, antes de intentar iniciar sesión, debes hacer una solicitud GET a /sanctum/csrf-cookie. Esto establece la cookie XSRF que Sanctum usará para las solicitudes subsiguientes (login, etc.).

    JavaScript
    // En tu SPA, al cargar la aplicación o antes del login
    fetch('http://localhost:8000/sanctum/csrf-cookie')
        .then(response => {
            // Ahora puedes proceder con la solicitud de login (POST /api/login)
            // que enviará automáticamente las cookies de sesión y CSRF.
        });
    

    Después de esto, las solicitudes de login y otras solicitudes API enviadas desde tu SPA al mismo dominio serán autenticadas a través de la cookie de sesión.


Otras Opciones de Autenticación de API en Laravel:

  1. Laravel Passport (OAuth2):

    • Cuándo usarlo: Si necesitas una solución OAuth2 completa para tu API, especialmente si vas a tener clientes de terceros (otras aplicaciones, no solo tu propia SPA/móvil) que necesiten interactuar con tu API y requerirán diferentes "grant types" (ej. Authorization Code, Client Credentials, Password Grant). Es más robusto y complejo que Sanctum.
    • Requiere: Instalación de laravel/passport y una configuración más extensa.
  2. JWT (JSON Web Tokens):

    • Cuándo usarlo: Si prefieres un enfoque completamente stateless y tienes experiencia con JWTs. Requiere una librería de terceros como tymon/jwt-auth. El token contiene toda la información del usuario en su interior (firmada, no cifrada).
    • Requiere: Instalación de tymon/jwt-auth y configuración manual del middleware.

¿Cuál elegir?

  • Para la mayoría de los casos (SPAs y aplicaciones móviles que tú controlas): Laravel Sanctum es la opción más sencilla, ligera y recomendada. Cubre perfectamente las necesidades de autenticación basada en tokens y sesiones para SPAs.
  • Para APIs públicas o si necesitas soporte OAuth2 completo (con diferentes tipos de "grants"): Laravel Passport es la solución adecuada.
  • Si tienes requisitos muy específicos o ya estás familiarizado con JWTs: tymon/jwt-auth puede ser una opción, pero para muchos, Sanctum ya cumple con los mismos objetivos de forma más integrada en Laravel.

Siempre recuerda la importancia de usar HTTPS para todas tus comunicaciones API, ya que los tokens se transmiten por la red.

Comentarios

Entradas populares de este blog

Crear proyecto de frontend con Vite, React, Tailwind, Typescript y JSX

 ¿Cómo se crea un proyecto exclusivo de frontend con Vite, React, Tailwind, Typescript y JSX? ¡Absolutamente! Entiendo que quieres la guía completa para pasar de cero a tener un proyecto de frontend moderno, vacío y listo para ser llenado con tu código. A continuación, te proporciono un archivo de guía detallada que incluye todos los comandos necesarios para inicializar el proyecto, configurar Tailwind CSS, y los pasos clave para empezar a "poblarlo". Voy a generar un documento Markdown con la guía paso a paso, incluyendo los comandos de terminal y las modificaciones esenciales a los archivos de configuración. Guía: Creación de un Proyecto Frontend Puro (Vite, React, TypeScript, Tailwind) Este documento detalla el proceso para inicializar un proyecto de frontend vacío y optimizado, utilizando Vite como empaquetador, React como librería, TypeScript para tipado y Tailwind CSS para estilizado. 1. Inicialización del Proyecto con Vite Vite es la herramienta más rápida para emp...

Tokens V2

Tokens: Programme to discover tokens, where there are not. Now available at  https://puszcza.gnu.org.ua/projects/tokens/ This is Version 2, for  version 1, go here . Synopsis: use TokensV2; sub printFile; my @FORMAT = ( ['<Message Date=".*?" Time=".*?" DateTime=".*?" SessionID=".*?"><From>(?:<User FriendlyName=".*?"/>)+</From><To>(?:<User FriendlyName=".*?"/>)+</To><Text(?: Style=".*?")?>.*?</Text></Message>',   sub {     my $fh = $_[1];     my ($d, $t, $f, $s, $T) = $_[0] =~ m|<Message Date="(.*?)" Time="(.*?)" DateTime=".*?" SessionID=".*?">(<From>(?:<User FriendlyName=".*?"/>)+</From>)<To>(?:<User FriendlyName=".*?"/>)+</To><Text(?: Style="(.*?)")?>(.*?)</Text></Message>|;     my $F = join '<br />', ...

Perl Net::LDAP::SimpleServer

Adaptaciones sobre el módulo LDAP Server para Windows (Strawberry Perl) Lista de adaptaciones (continúa más abajo): - Relajación de condiciones de bind:     - Cuenta principal (principal account)     - Validación de contraseñas Ubicación del archivo: %Strawberry_Perl%\site\lib\net\ldap\SimpleServer\ProtocolHandler.pm CPAN: http://search.cpan.org/~russoz/Net-LDAP-SimpleServer-0.0.17/lib/Net/LDAP/SimpleServer.pm Código: package Net::LDAP::SimpleServer::ProtocolHandler; use strict; use warnings; # ABSTRACT: LDAP protocol handler used with Net::LDAP::SimpleServer our $VERSION = '0.0.17';    # VERSION use Net::LDAP::Server; use base 'Net::LDAP::Server'; use fields qw(store root_dn root_pw allow_anon); use Carp; use Net::LDAP::LDIF; use Net::LDAP::Util qw{canonical_dn}; use Net::LDAP::FilterMatch; use Net::LDAP::Constant (     qw/LDAP_SUCCESS LDAP_AUTH_UNKNOWN LDAP_INVALID_CREDENTIALS/,   ...