Autenticación SPA con Sanctum en Laravel

Author
Por Darío Rivera
Publicado el en Laravel

Uno de los dos problemas que intenta resolver Laravel Sanctum es el hecho de autenticar una aplicación frontend con el backend de laravel. Para esto, laravel utiliza un CSRF token o cookie autenticada y una cookie de sessión.

El siguiente diagrama representa el flujo de autenticación de una aplicación con el backend de laravel.

flujo de autenticación spa en laravel

Nota que en la representación del flujo se pueden apreciar tres consumos a la API. En el primero de obtiene el CSRF-TOKEN que será utilizado en el endpoint de /login. Este segundo endpoint devolverá otro CSRF-TOKEN autenticado el cual puede ser utilizado para llamadas posteriores a la API en donde se autentique con auth:sanctum.

Obtener el CSRF Token

En primer lugar, debes saber que Laravel utiliza cookies para autenticar los solicitudes entrantes en la API. Estas cookies son XSRF-TOKEN y laravel_session. Para obtenerlas no debes hacer más que consumir el siguiente endpoint usando el método HTTP GET.

GET /sanctum/csrf-cookie HTTP/1.1

Obtendrás una respuesta muy similar a la siguiente.

HTTP/1.1 204 No Content
Access-Control-Allow-Origin: http://yourdomain.com
Access-Control-Allow-Credentials: true
Set-Cookie: XSRF-TOKEN=eyJpdiI6ImZDNnNOQStVdnd1U0hoYTl0dUhaRkE9PSIsInZhbHVlIjoiMURDZGp2azRpRE00Tk1sRXdTTDUzaG11NDVxWW9ScTlvQ0V3aFM5Mnh4VzROSXFXY3VUSFVnMzNlcTVmbmRNRUs4WlZ1K0ZyWElZREpIVkFNZW9PT3UyN0ZtWUp5Z3RXYmxCdWUyRUZtVnE5d3NFWTI1NmpqR240WXFHOHkzVmUiLCJtYWMiOiIzYWU3MjViYmVjYmNiNWU3ZGI0MWY0ZWEzY2VmMGYwYTA3MzIyMjQzMzFhNzM5ODEyOWJmOGMxMTEzMzViZjY2IiwidGFnIjoiIn0%3D; expires=Fri, 18 Aug 2023 04:32:02 GMT; Max-Age=7200; path=/; samesite=lax
Set-Cookie: laravel_session=eyJpdiI6IjAvT1dkaXJvbDNiTXZQL0crVG11Z1E9PSIsInZhbHVlIjoicm5RRWJKV1ZjUWd6YnN2WDVMZmN1WDNYcEdrREF5NzJBb0t4RnUzWEkvRXUyNWc4Q24vanNNQ3NLTUhrczdkNEEvelFSM3Iwb3RHVEE4eXhPZE5COTBmQWJkVXh3a1BnbjErT3NXSkR0Ri9ZK0hBKzVHbG5OVHdFRXplSkZWMWsiLCJtYWMiOiJmMzg2ZGNjOGMxN2FhMWM5N2Q5OGU2YmNmMDE0ZjkyMzI2ZWY4ZGY1MGE4NDc5MGEyYzU5MTcwNjE2NTA5OWQyIiwidGFnIjoiIn0%3D; expires=Fri, 18 Aug 2023 04:32:02 GMT; Max-Age=7200; path=/; httponly; samesite=lax

El header Access-Control-Allow-Credentials nos indica que la respuesta de la API puede ser usada por aplicaciones front-end o javascript.

El header Access-Control-Allow-Origin nos indica el dominio que puede acceder a dicho recurso. Este header es siempre enviado cuando "allow credentials" es true.

Por simplicidad, de ahora en adelante utilizaremos valores más cortos para las cookies. Supongamos que las cookies que envió el servidor fueron las siguientes, las cuales no son más que valores representativos del valor real de la cookie.

XSRF-TOKEN: csrfXsrfToken
laravel_session: csrfLaravelSesion

Presta mucha atención a los valores generados, ya que se utilizarán en pasos posteriores.

Autenticarse en la API

Para consumir el endpoint de autenticación debes haber consumido previamente el endpoint para obtener el CSRF Token y la sesión de laravel. Estos valores deben enviarse en el header cookie. Además de esto, debes enviar el XSRF-TOKEN como request header.

POST /login HTTP/1.1
Content-Type: application/json
Accept: application/json
Cookie: laravel_session=csrfLaravelSesion; XSRF-TOKEN=csrfXsrfToken
XSRF-TOKEN: csrfXsrfToken
laravel_session: csrfLaravelSesion

{
    "email": "admin@admin.com",
    "password": "password"
}

De hecho, XSRF-TOKEN en las cookies es meramente opcional ya que también está siendo enviado como header. Obtendrás una respuesta muy similar a la siguiente. Observa que las cookies han sido enviadas nuevamente por laravel con valores diferentes.

HTTP/1.1 204 No Content
Access-Control-Allow-Origin: http://yourdomain.com
Access-Control-Allow-Credentials: true
Set-Cookie: XSRF-TOKEN=loginXsrfToken
Set-Cookie: laravel_session=loginLaravelSession

Reitero, los valores de las cookies han sido simplificados para efectos de este post.

Consumir la API usando la sesión de autenticación

Una vez obtienes una respuesta satisfactoria del endpoint de autenticación puedes empezar a consumir cualquier otro endpoint que use el middleware auth:sanctum.

Supongamos que creaste un nuevo controlador llamado UserModelsController. Para proteger el nuevo endpoint debes usar el middleware de sanctum de la siguiente forma.

Route::middleware(['auth:sanctum'])
    ->resource('user-models', UserModelsController::class);

Además, debes haber configurado previamente una de las siguientes dos variables en laravel.

APP_URL=http://yourdomain.com
FRONTEND_URL=http://yourdomain.com

Una vez hecho esto puedes realizar la petición agregando token obtenido del endpoint de autenticación y última sesión de laravel debe ser agregada al header cookie.

POST /api/user-models HTTP/1.1
Content-Type: application/json
Accept: application/json
origin: http://yourdomain.com
Cookie: laravel_session=loginLaravelSesion
XSRF-TOKEN: loginXsrfToken

{
   "user_id": 1,
   "mode_name": "model name"
}

Para que la petición pueda ser autenticada debes enviear el header origin con el dominio permitido para consumir la API. Si no envías el dominio habilitado obtendrás un error de autenticación. Este dominio es el mismo que debiste recibir en el header Access-Control-Allow-Origin.

Una vez obtienes una respuesta satisfactoria de tu endpoint obtendrás nuevos headers. De esos headers debes enviar nuevamente laravel_session. Sin embargo, podrás seguir utilizando el mismo valor para XSRF-TOKEN hasta que expire. De todas formas, es siempre recomendable enviar el último valor obtenido.


Acerca de Darío Rivera

Author

Application Architect at Elentra Corp . Quality developer and passionate learner with 10+ years of experience in web technologies. Creator of EasyHttp , an standard way to consume HTTP Clients.

LinkedIn Twitter Instagram

Sólo aquellos que han alcanzado el éxito saben que siempre estuvo a un paso del momento en que pensaron renunciar.