¿Los request de las rutas que van en api.php siempre son stateless? ¿Y los request de las rutas que van en web.php siempre son statefull?
¡Es una excelente pregunta! La distinción entre api.php
y web.php
es fundamental para entender cómo Laravel maneja las solicitudes, especialmente en relación con la autenticación y el estado de la sesión.
Rutas en api.php
: Stateless
Sí, las rutas definidas en el archivo routes/api.php
son siempre stateless (sin estado) por defecto. Esto significa que Laravel no utiliza cookies ni sesiones para rastrear al usuario a través de múltiples solicitudes.
¿Por qué es esto?
Las APIs se diseñan para ser consumidas por aplicaciones cliente que pueden no ser navegadores web (como aplicaciones móviles o scripts del servidor). Estos clientes no siempre manejan cookies de la misma manera que un navegador.
En una API sin estado, cada solicitud es un evento independiente. El cliente debe proporcionar alguna forma de autenticación (como un token de API o un token JWT) con cada solicitud, y el servidor verifica la validez de ese token en cada petición. Esto es ideal para arquitecturas SPA (Single Page Application) y microservicios, ya que permite que la aplicación cliente esté desacoplada de la sesión de Laravel.
Laravel aplica un middleware especial a estas rutas (api
en el archivo app/Http/Kernel.php
), que incluye una capa de "limitación de velocidad" y la configuración para el manejo de tokens.
Rutas en web.php
: Statefull
Las rutas en routes/web.php
son siempre statefull (con estado) por defecto. Esto significa que Laravel utiliza cookies y sesiones para mantener un seguimiento del usuario a lo largo del tiempo.
¿Por qué es esto?
Las aplicaciones web tradicionales, diseñadas para ser renderizadas por el servidor, se basan en la sesión para funcionar. Cuando un usuario inicia sesión, el servidor guarda su información en la sesión y le envía al navegador una cookie de sesión.
En las siguientes solicitudes, el navegador envía automáticamente esta cookie, y Laravel puede usarla para identificar al usuario y mantener su estado de sesión (por ejemplo, saber si está autenticado, su carrito de compras, etc.).
El grupo de middleware que Laravel aplica a las rutas web incluye
\Illuminate\Session\Middleware\StartSession
y\App\Http\Middleware\VerifyCsrfToken
, que son esenciales para el manejo del estado de la sesión y la seguridad.
En resumen, la distinción principal no es que un tipo de solicitud sea fundamentalmente diferente, sino que Laravel les aplica diferentes middlewares para que se comporten de manera que tenga sentido para sus respectivos casos de uso: API sin estado y Web con estado.
Un request de api puede ser tratado como statefull por medio de sanctum?
Sí, ¡esa es la magia de Sanctum!
El propósito principal de Sanctum es cerrar la brecha entre las APIs sin estado y la necesidad de tener una autenticación con estado en una aplicación de una sola página (SPA) que se ejecuta en el navegador.
¿Cómo funciona?
Sanctum te permite usar la misma autenticación basada en cookies que las rutas de web.php
para tus rutas en api.php
. Esto es lo que sucede detrás de bambalinas:
Negociación de Origen Cruzado: Cuando tu SPA (
spa.test
) hace una solicitud a tu backend (api.test
), el navegador inicia un "handshake" (saludo) de CORS. El navegador envía la cookie de sesión de tu dominio de la API.Verificación de la cookie: Sanctum intercepta la solicitud. En lugar de buscar un token de API en la cabecera
Authorization
, busca la cookie de sesión de Laravel.Aprobación: Si el usuario está autenticado en esa sesión (es decir, la cookie es válida), Sanctum valida la petición y la permite continuar como si fuera una solicitud con estado.
Esencialmente, Sanctum es un guardián de autenticación para las rutas API que te permite usar tanto tokens de portador (bearer tokens) para clientes móviles como cookies para tu SPA.
¿Cuándo usarlo?
SPA: Cuando estás construyendo una aplicación de una sola página (SPA) con un framework como Vue, React o Angular. Las cookies son la forma más sencilla de manejar la autenticación en este escenario.
API y Web: Cuando necesitas una API que pueda ser consumida tanto por tu aplicación web (que usa cookies) como por otras aplicaciones (que usarán tokens de portador).
Sanctum hace que un "request de api" se comporte de una manera híbrida. Por un lado, sigue siendo una API sin estado en el sentido de que no depende de la sesión de Laravel. Pero por otro, usa la identidad de la sesión para autenticar al usuario, lo que lo hace parecer con estado.
Va bien todo esto con Inertia?
Absolutamente, ¡Sanctum y Inertia van de la mano a la perfección!
¿Por qué Inertia y Sanctum funcionan tan bien juntos?
Inertia.js está diseñado para funcionar como una aplicación de una sola página (SPA) sin el "dolor de cabeza" de una API. Esto significa que usa las rutas de web.php
de Laravel y el sistema de sesión/cookies que ya conoces, lo que evita la necesidad de tokens de portador o la complejidad de CORS.
Sin embargo, en el fondo, Inertia sigue siendo una SPA que se comunica con tu servidor a través de peticiones XHR/AJAX. Aquí es donde Sanctum se vuelve útil, aunque de una manera un poco diferente a la que describimos anteriormente.
Manejo del CSRF: Inertia, por defecto, se encarga de enviar el token CSRF (no el XSRF) de la cookie de Laravel con cada petición
POST
,PUT
oDELETE
. Para las peticiones de Inertia, el token CSRF es lo que valida el formulario y asegura que la solicitud provenga de la aplicación.Autenticación sin problemas: Cuando un usuario inicia sesión en tu aplicación Inertia, el servidor de Laravel crea una cookie de sesión (
laravel_session
). Cada petición subsiguiente de Inertia al servidor (a través de Inertia.js) incluye automáticamente esta cookie de sesión. El servidor de Laravel reconoce la cookie, sabe que el usuario está autenticado y maneja la petición sin ningún problema.
Conclusión
La combinación de Inertia y Sanctum es tan efectiva que a menudo se le conoce como el "modelo SPA-amistoso" de Laravel. Sanctum proporciona el middleware necesario para las rutas api.php
, permitiendo que Inertia se comunique con el servidor de manera segura y sin complicaciones.
No necesitas hacer nada especial. Simplemente configura Inertia.js para que utilice tus rutas de web.php
, y Sanctum se encargará del resto, asegurando que tus peticiones con AJAX sean seguras, ¡como si fueran una solicitud de formulario normal!
Quiero hacer yo las peticiones Ajax de manera explícita con fetch. ¿Las rutas las creo en web.php o en api.php?
Las rutas para tus peticiones fetch
deben ir en api.php
.
¿Por qué api.php
?
Aunque técnicamente podrías usar web.php
, usar api.php
es la práctica recomendada y la más segura por las siguientes razones:
Protección CSRF: Las rutas en
web.php
requieren un token CSRF (Cross-Site Request Forgery) para las solicitudesPOST
,PUT
yDELETE
. Este token se incluye automáticamente si usas formularios o librerías como Inertia, pero si haces peticionesfetch
manuales, tendrás que asegurarte de obtener el token de la cookie y enviarlo en la cabeceraX-XSRF-TOKEN
con cada solicitud. Es un paso extra que puede complicar tu código.Middlewares de API: Laravel ya tiene una pila de middlewares optimizada para APIs en el archivo
api.php
. Estos middlewares gestionan la autenticación sin estado (con tokens de portador) y la limitación de peticiones (rate limiting), que son ideales para peticiones AJAX.Coherencia y organización: Poner tus rutas AJAX en
api.php
mantiene tu código organizado. Las rutas deweb.php
se usan para las páginas de tu aplicación (vistas de blade o componentes de Inertia), mientras que las rutas deapi.php
se usan para los endpoints que devuelven datos (JSON) para tu frontend.
Ejemplo de cómo hacerlo
Aquí tienes un ejemplo de cómo crear una ruta en api.php
y cómo hacer la petición fetch
desde tu JavaScript.
1. Define la ruta en routes/api.php
:
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
// Agregamos el middleware 'auth:sanctum' para proteger la ruta
Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
return $request->user();
});
2. Haz la petición fetch
desde tu JavaScript:
Para que fetch
funcione con Sanctum, necesitas la configuración adecuada. Aquí está un ejemplo completo de cómo configurar y usar fetch
:
El ejemplo anterior te muestra cómo:
Hacer la primera petición a
sanctum/csrf-cookie
para obtener la cookie de sesión de Laravel.Hacer una segunda petición a una ruta de la API protegida con el middleware
auth:sanctum
.
El navegador se encarga automáticamente de enviar la cookie en las siguientes peticiones a tu dominio, y Sanctum se encarga de autenticar al usuario usando esa cookie.
Necesito una app con Inertia que además consuma una API, y que esta API se base los mismos mecanismos de seguridad que la aplicación Inertia.
¡Excelente pregunta! Esta es una de las mayores fortalezas de Laravel Sanctum. No solo te protege con las cookies de sesión para tu aplicación Inertia, sino que también te permite usar el mismo sistema de autenticación para tus propias peticiones fetch
a la API.
No necesitas tokens de portador ni ninguna otra configuración compleja. Sanctum se encarga de todo esto por ti.
Aquí tienes un ejemplo completo que simula una aplicación de una sola página (SPA) que se autentica a través de Sanctum. Este código te mostrará cómo las peticiones a la API y las peticiones a tus rutas web utilizan el mismo mecanismo de seguridad, todo gracias a la cookie de sesión de Laravel.
Cómo funciona
Inicio de Sesión (SPA Authentication): Al hacer clic en "Iniciar Sesión", la aplicación hace una petición a la ruta
sanctum/csrf-cookie
. Esto hace que Laravel cree una cookie de sesión con el token CSRF y la envíe al navegador.Peticiones Automáticas: Una vez que el navegador tiene la cookie de sesión, la adjuntará automáticamente a todas las peticiones posteriores a ese dominio (tanto a tus rutas web como a tus rutas de
api.php
).Sanctum en Acción: Sanctum, usando su middleware
auth:sanctum
, intercepta estas peticiones. Si detecta la cookie de sesión, autentica al usuario sin necesidad de un token de portador. Esto hace que tu API sea segura de forma nativa para tu frontend SPA.
Este enfoque te permite mantener toda tu lógica de seguridad centralizada y te evita tener que gestionar tokens de forma manual en tu frontend. ¡Es una solución limpia y robusta para tu proyecto!
¿La URL /sanctum/csrf-cookie es un endpoint, una ruta, u otra cosa? ¿No es inseguro que devuelva una cookie de sesión sin pedir credenciales a cambio?
Tu pregunta es excelente y toca un punto clave de la seguridad. Es muy perspicaz.
La URL /sanctum/csrf-cookie
es una ruta (un endpoint). Su propósito principal no es autenticarte, sino iniciar el "protocolo" de comunicación entre tu SPA y Laravel.
¿Por qué no es inseguro?
El hecho de que esta ruta devuelva una cookie sin pedir credenciales no la hace insegura, porque la cookie en sí misma no concede acceso a los datos de tu usuario. Piensa en ella como una llave de entrada que te permite pasar por la primera puerta, pero no te abre las puertas de la casa.
Aquí está el desglose:
Petición 1:
/sanctum/csrf-cookie
Lo que hace: Esta petición inicial le dice a Laravel: "Hola, soy una SPA y necesito comunicarme contigo".
Lo que devuelve: Laravel responde con una cookie de sesión (que contiene un token CSRF). Esta cookie es simplemente un identificador de sesión. No sabe quién eres, solo que eres un "visitante" en ese momento. Esta cookie es el pegamento que unirá tus futuras peticiones con la sesión de Laravel.
Seguridad: No se pide autenticación porque no se está accediendo a datos protegidos. Esta ruta es pública y solo sirve para establecer el estado de la sesión.
Petición 2:
/api/user
(u otra ruta protegida)Lo que hace: Tu navegador envía esta petición a la API, adjuntando automáticamente la cookie de sesión que recibió antes.
Lo que comprueba Laravel: Ahora sí, el middleware de autenticación de Laravel (
auth:sanctum
) entra en juego. Comprueba si la cookie de sesión está asociada a un usuario autenticado.Autenticación: Si el usuario ha iniciado sesión previamente (por ejemplo, a través de una página de
login
), Laravel encontrará el usuario en la sesión y permitirá el acceso. Si el usuario no ha iniciado sesión, la petición fallará con un error401 Unauthorized
(no autorizado), sin importar que tengas la cookie de sesión.
La distinción clave: ¿Quién eres vs. qué puedes hacer?
La cookie de sesión de /sanctum/csrf-cookie
solo identifica la sesión de un visitante, no la identidad de un usuario. Es el proceso de autenticación posterior (por ejemplo, enviando las credenciales de inicio de sesión a otra ruta) lo que vincula la sesión con un usuario específico. Una vez que esa vinculación ocurre, la misma cookie se usa para proteger todas las peticiones futuras, tanto en la web como en la API, asegurando que solo el usuario correcto pueda acceder a sus datos.
Es una estrategia segura y eficiente que evita la complejidad de gestionar tokens de portador en el lado del cliente.
Mi app usa el login del starterkit de Inertia/React, con cierta modificación que incorporé, pero que en definitiva termina llamando a Auth::login($user, $this->boolean('remember'));. Creo que en mi caso no tengo que llamar a /sanctum/csrf-cookie ni antes ni después de hacer el login. ¿Estoy acertado?
Sí, estás completamente en lo cierto. No necesitas llamar a /sanctum/csrf-cookie
ni antes ni después de tu proceso de inicio de sesión con el starter kit de Inertia.js.
¿Por qué Inertia lo hace por ti?
El starter kit de Inertia está diseñado para que te olvides de esta complejidad. Cuando el navegador realiza una solicitud GET
a la ruta de login para mostrar la vista, el servidor de Laravel automáticamente establece la cookie de sesión.
La magia ocurre cuando envías el formulario de login. Inertia.js sabe que está haciendo una solicitud POST
y, gracias a su configuración por defecto, automáticamente toma el token CSRF de la cookie de sesión y lo incluye en la cabecera de la petición X-XSRF-TOKEN
.
Por lo tanto, la secuencia es la siguiente:
El navegador carga la página de inicio de sesión de Inertia.
Laravel envía al navegador una respuesta HTML que incluye la cookie de sesión con el token CSRF.
El usuario introduce sus credenciales y hace clic en "Login".
Inertia intercepta la petición, añade el token CSRF a la cabecera de la solicitud y la envía a Laravel.
Laravel, a través de sus middlewares, valida el token CSRF y autentica al usuario.
La llamada a
Auth::login()
asocia el usuario a la sesión actual, y la cookie de sesión permanece activa para las siguientes peticiones.
En esencia, Inertia/React y el starter kit de Laravel ya han implementado la lógica para el "handshake" de Sanctum por ti. No tienes que preocuparte por hacerlo de manera manual.
¿Alcanza el nivel de seguridad sin la protección del middleware auth:sanctum en las rutas de api.php?
No, no es seguro. Si tus rutas de api.php
no tienen el middleware auth:sanctum
(o cualquier otro middleware de autenticación), están completamente desprotegidas. Cualquiera podría acceder a ellas, incluso si el usuario no ha iniciado sesión.
¿Cómo funciona la seguridad en tu caso?
El starter kit de Inertia.js está diseñado para funcionar en conjunto con las rutas protegidas de Laravel.
Protección de rutas web: El middleware
web
que se aplica a las rutas deweb.php
ya contieneauth
,StartSession
yVerifyCsrfToken
. Esto protege automáticamente las páginas de tu aplicación.Protección de rutas de API: El middleware
auth:sanctum
de las rutas deapi.php
es el que realmente verifica la autenticidad de las peticiones. Cuando tu aplicación de Inertia hace una llamada a unendpoint
de la API, el navegador envía la cookie de sesión. El middlewareauth:sanctum
de Laravel es el responsable de interceptar esa cookie, verificar si pertenece a un usuario autenticado y permitir el acceso. Sin este middleware, la API simplemente serviría los datos a quien los pida.
En resumen, el hecho de que uses el login de Inertia no significa que tus rutas de API sean seguras por arte de magia. Tienes que aplicar el middleware auth:sanctum
para que las peticiones a la API sean seguras.
No te preocupes, el auth:sanctum
es lo que te permite usar las cookies de sesión para proteger tu API de la misma forma que tu aplicación web. Sin él, tu API estaría abierta al público.