1. Paquetes
  2. Laravel Sanctum

Introducción

Laravel Sanctum proporciona un sistema de autenticación liviano para SPAs (aplicaciones de página única), aplicaciones móviles y API simples basadas en tokens. Sanctum permite que cada usuario de tu aplicación genere múltiples tokens de API para su cuenta. Estos tokens pueden recibir habilidades o alcances que especifican qué acciones se les permite realizar.

Cómo Funciona

Laravel Sanctum existe para resolver dos problemas diferentes. Vamos a discutir cada uno antes de profundizar más en la biblioteca.

Tokens de API

En primer lugar, Sanctum es un paquete simple que puedes utilizar para emitir tokens de API a tus usuarios sin la complicación de OAuth. Esta función está inspirada en GitHub y otras aplicaciones que emiten "tokens de acceso personal". Por ejemplo, imagina que la "configuración de la cuenta" de tu aplicación tiene una pantalla donde un usuario puede generar un token de API para su cuenta. Puedes usar Sanctum para generar y gestionar esos tokens. Estos tokens suelen tener un tiempo de caducidad muy largo (años), pero pueden revocarse manualmente por el usuario en cualquier momento.

Laravel Sanctum ofrece esta función almacenando los tokens de API del usuario en una sola tabla de base de datos y autenticando las solicitudes HTTP entrantes mediante la cabecera Authorization, que debe contener un token de API válido.

Autenticación SPA

En segundo lugar, Sanctum existe para ofrecer una forma sencilla de autenticar aplicaciones de página única (SPAs) que necesitan comunicarse con una API impulsada por Laravel. Estas SPAs pueden existir en el mismo repositorio que tu aplicación Laravel o pueden ser un repositorio completamente separado, como una SPA creada con Vue CLI o una aplicación Next.js.

Para esta función, Sanctum no utiliza tokens de ningún tipo. En su lugar, Sanctum utiliza los servicios de autenticación de sesión basados en cookies integrados de Laravel. Típicamente, Sanctum utiliza la guarda de autenticación web de Laravel para lograr esto. Esto proporciona los beneficios de protección CSRF, autenticación de sesión, así como protege contra la filtración de las credenciales de autenticación mediante XSS.

Sanctum solo intentará autenticar mediante cookies cuando la solicitud entrante se origine desde tu propio frontend de SPA. Cuando Sanctum examina una solicitud HTTP entrante, primero verificará si hay una cookie de autenticación y, si no hay ninguna presente, Sanctum examinará la cabecera Authorization en busca de un token de API válido.

Nota Es completamente válido usar Sanctum solo para la autenticación con tokens de API o solo para la autenticación SPA. Solo porque uses Sanctum no significa que estés obligado a utilizar ambas funciones que ofrece.

Instalación

Nota Las versiones más recientes de Laravel ya incluyen Laravel Sanctum. Sin embargo, si el archivo composer.json de tu aplicación no incluye laravel/sanctum, puedes seguir las instrucciones de instalación a continuación.

Puedes instalar Laravel Sanctum a través del administrador de paquetes Composer:

composer require laravel/sanctum

A continuación, debes publicar los archivos de configuración y migración de Sanctum usando el comando Artisan vendor:publish. El archivo de configuración sanctum se ubicará en el directorio config de tu aplicación:

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

Finalmente, debes ejecutar las migraciones de tu base de datos. Sanctum creará una tabla de base de datos en la que almacenará los tokens de API:

php artisan migrate

Después, si planeas utilizar Sanctum para autenticar una SPA, debes agregar el middleware de Sanctum al grupo de middleware api dentro del archivo app/Http/Kernel.php de tu aplicación:

'api' => [
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
\Illuminate\Routing\Middleware\ThrottleRequests::class.':api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],

Personalización de Migración

Si no vas a utilizar las migraciones predeterminadas de Sanctum, debes llamar al método Sanctum::ignoreMigrations en el método register de tu clase App\Providers\AppServiceProvider. Puedes exportar las migraciones predeterminadas ejecutando el siguiente comando: php artisan vendor:publish --tag=sanctum-migrations

Configuración

Anulación de Modelos Predeterminados

Aunque normalmente no es necesario, eres libre de extender el modelo PersonalAccessToken utilizado internamente por Sanctum:

use Laravel\Sanctum\PersonalAccessToken as SanctumPersonalAccessToken;
 
class PersonalAccessToken extends SanctumPersonalAccessToken
{
// ...
}

Luego, puedes indicar a Sanctum que use tu modelo personalizado mediante el método usePersonalAccessTokenModel proporcionado por Sanctum. Por lo general, debes llamar a este método en el método boot de uno de los proveedores de servicios de tu aplicación:

use App\Models\Sanctum\PersonalAccessToken;
use Laravel\Sanctum\Sanctum;
 
/**
* Inicializa cualquier servicio de la aplicación.
*/
public function boot(): void
{
Sanctum::usePersonalAccessTokenModel(PersonalAccessToken::class);
}

Autenticación con Token de API

Nota No debes usar tokens de API para autenticar tu propio SPA de primeros usuarios. En su lugar, utiliza las funciones integradas de autenticación SPA de Sanctum.

Emisión de Tokens de API

Sanctum te permite emitir tokens de API/tokens de acceso personal que se pueden utilizar para autenticar las solicitudes de la API de tu aplicación. Al realizar solicitudes mediante tokens de API, el token debe incluirse en la cabecera Authorization como un token Bearer.

Para comenzar a emitir tokens para los usuarios, tu modelo de usuario debe usar el rasgo Laravel\Sanctum\HasApiTokens:

use Laravel\Sanctum\HasApiTokens;
 
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
}

Para emitir un token, puedes usar el método createToken. El método createToken devuelve una instancia de Laravel\Sanctum\NewAccessToken. Los tokens de API se hashan mediante el hashing SHA-256 antes de almacenarse en tu base de datos, pero puedes acceder al valor en texto sin formato del token utilizando la propiedad plainTextToken de la instancia NewAccessToken. Debes mostrar este valor al usuario inmediatamente después de crear el token:

use Illuminate\Http\Request;
 
Route::post('/tokens/create', function (Request $request) {
$token = $request->user()->createToken($request->token_name);
 
return ['token' => $token->plainTextToken];
});

Puedes acceder a todos los tokens del usuario utilizando la relación Eloquent tokens proporcionada por el rasgo HasApiTokens:

foreach ($user->tokens as $token) {
// ...
}

Habilidades del Token

Sanctum te permite asignar "habilidades" a los tokens. Las habilidades cumplen un propósito similar a los "alcances" de OAuth. Puedes pasar un array de habilidades como segundo argumento al método createToken:

return $user->createToken('token-name', ['server:update'])->plainTextToken;

Cuando manejas una solicitud entrante autenticada por Sanctum, puedes determinar si el token tiene una habilidad específica utilizando el método tokenCan:

if ($user->tokenCan('server:update')) {
// ...
}

Middleware de Habilidades del Token

Sanctum también incluye dos middleware que se pueden utilizar para verificar que una solicitud entrante esté autenticada con un token al que se le haya otorgado una habilidad específica. Para comenzar, agrega los siguientes middleware a la propiedad $middlewareAliases de tu archivo app/Http/Kernel.php de la aplicación:

'abilities' => \Laravel\Sanctum\Http\Middleware\CheckAbilities::class,
'ability' => \Laravel\Sanctum\Http\Middleware\CheckForAnyAbility::class,

El middleware abilities se puede asignar a una ruta para verificar que el token de la solicitud entrante tenga todas las habilidades enumeradas:

Route::get('/orders', function () {
// El token tiene tanto las habilidades "check-status" como "place-orders"...
})->middleware(['auth:sanctum', 'abilities:check-status,place-orders']);

El middleware ability se puede asignar a una ruta para verificar que el token de la solicitud entrante tenga al menos una de las habilidades enumeradas:

Route::get('/orders', function () {
// El token tiene la habilidad "check-status" o "place-orders"...
})->middleware(['auth:sanctum', 'ability:check-status,place-orders']);

Solicitudes Iniciadas por Interfaz de Usuario de Primeros Usuarios

Para mayor comodidad, el método tokenCan siempre devolverá true si la solicitud autenticada entrante provino de tu SPA de primeros usuarios y estás utilizando la autenticación SPA integrada de Sanctum.

Sin embargo, esto no significa necesariamente que tu aplicación deba permitir que el usuario realice la acción. Típicamente, las políticas de autorización de tu aplicación determinarán si se ha otorgado al token el permiso para realizar las habilidades y también verificarán si la instancia de usuario en sí misma tiene permitido realizar la acción.

Por ejemplo, si imaginamos una aplicación que gestiona servidores, esto podría significar verificar que el token está autorizado para actualizar servidores y que el servidor pertenece al usuario:

return $request->user()->id === $server->user_id &&
$request->user()->tokenCan('server:update')

Al principio, permitir que se llame al método tokenCan y que siempre devuelva true para las solicitudes iniciadas por la interfaz de usuario de primeros usuarios puede parecer extraño; sin embargo, es conveniente poder asumir siempre que hay un token de API disponible y se puede inspeccionar mediante el método tokenCan. Al adoptar este enfoque, siempre puedes llamar al método tokenCan dentro de las políticas de autorización de tu aplicación sin preocuparte por si la solicitud se activó desde la interfaz de usuario de tu aplicación o fue iniciada por uno de los consumidores de tu API de terceros.

Protección de Rutas

Para proteger rutas de modo que todas las solicitudes entrantes deban estar autenticadas, debes adjuntar la guarda de autenticación sanctum a tus rutas protegidas dentro de tus archivos de ruta routes/web.php y routes/api.php. Esta guarda se asegurará de que las solicitudes entrantes estén autenticadas como solicitudes autenticadas por cookies o contengan una cabecera de token de API válida si la solicitud es de un tercero.

Puede que te preguntes por qué sugerimos que autentiques las rutas dentro del archivo routes/web.php de tu aplicación utilizando la guarda sanctum. Recuerda, Sanctum intentará primero autenticar las solicitudes entrantes utilizando la cookie de autenticación típica de Laravel. Si esa cookie no está presente, Sanctum intentará autenticar la solicitud utilizando un token en la cabecera Authorization de la solicitud. Además, autenticar todas las solicitudes utilizando Sanctum garantiza que siempre podamos llamar al método tokenCan en la instancia de usuario autenticada actualmente:

use Illuminate\Http\Request;
 
Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
return $request->user();
});

Revocación de Tokens

Puedes "revocar" tokens eliminándolos de tu base de datos utilizando la relación tokens proporcionada por el rasgo Laravel\Sanctum\HasApiTokens:

// Revoca todos los tokens...
$user->tokens()->delete();
 
// Revoca el token que se utilizó para autenticar la solicitud actual...
$request->user()->currentAccessToken()->delete();
 
// Revoca un token específico...
$user->tokens()->where('id', $tokenId)->delete();

Vencimiento del Token

Por defecto, los tokens de Sanctum nunca caducan y solo pueden invalidarse revocando el token. Sin embargo, si deseas configurar un tiempo de caducidad para los tokens de API de tu aplicación, puedes hacerlo a través de la opción de configuración expiration definida en el archivo de configuración sanctum de tu aplicación. Esta opción de configuración define la cantidad de minutos hasta que se considere que un token emitido ha caducado:

'expiration' => 525600,

Si has configurado un tiempo de caducidad del token para tu aplicación, también puedes programar una tarea para eliminar los tokens caducados de tu aplicación. Afortunadamente, Sanctum incluye un comando Artisan sanctum:prune-expired que puedes utilizar para lograr esto. Por ejemplo, puedes configurar una tarea programada para eliminar todos los registros de tokens caducados que hayan caducado durante al menos 24 horas:

$schedule->command('sanctum:prune-expired --hours=24')->daily();

Autenticación SPA

Sanctum también existe para proporcionar un método simple de autenticar aplicaciones de página única (SPAs) que necesitan comunicarse con una API alimentada por Laravel. Estas SPAs pueden existir en el mismo repositorio que tu aplicación de Laravel o pueden ser un repositorio completamente separado.

Para esta función, Sanctum no utiliza tokens de ningún tipo. En su lugar, Sanctum utiliza los servicios de autenticación de sesión basados en cookies integrados de Laravel. Este enfoque de autenticación proporciona los beneficios de protección contra CSRF, autenticación de sesión, así como protección contra la filtración de las credenciales de autenticación mediante XSS.

Advertencia Para autenticarte, tu SPA y API deben compartir el mismo dominio de nivel superior. Sin embargo, pueden estar en subdominios diferentes. Además, asegúrate de enviar la cabecera Accept: application/json y ya sea la cabecera Referer o Origin con tu solicitud.

Configuración

Configuración de Tus Dominios de Primeros Usuarios

Primero, debes configurar qué dominios realizarán solicitudes desde tu SPA. Puedes configurar estos dominios mediante la opción de configuración stateful en tu archivo de configuración sanctum. Esta configuración determina qué dominios mantendrán la autenticación "con estado" utilizando cookies de sesión de Laravel al realizar solicitudes a tu API.

Advertencia Si accedes a tu aplicación a través de una URL que incluye un puerto (127.0.0.1:8000), asegúrate de incluir el número de puerto con el dominio.

Middleware Sanctum

A continuación, debes agregar el middleware de Sanctum al grupo de middleware api dentro de tu archivo app/Http/Kernel.php. Este middleware se encarga de garantizar que las solicitudes entrantes desde tu SPA puedan autenticarse mediante las cookies de sesión de Laravel, al tiempo que permite que las solicitudes de terceros o aplicaciones móviles se autentiquen mediante tokens de API:

'api' => [
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
\Illuminate\Routing\Middleware\ThrottleRequests::class.':api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],

CORS y Cookies

Si tienes problemas para autenticarte con tu aplicación desde una SPA que se ejecuta en un subdominio separado, es probable que hayas configurado incorrectamente tus ajustes de CORS (Recursos Compartidos de Origen Cruzado) o cookies de sesión.

Asegúrate de que la configuración CORS de tu aplicación esté devolviendo la cabecera Access-Control-Allow-Credentials con un valor de True. Esto se puede lograr configurando la opción supports_credentials dentro del archivo de configuración config/cors.php de tu aplicación en true.

Además, debes habilitar la opción withCredentials en la instancia global de axios de tu aplicación. Normalmente, esto se debe hacer en tu archivo resources/js/bootstrap.js. Si no estás utilizando Axios para realizar solicitudes HTTP desde tu frontend, debes realizar la configuración equivalente en tu propio cliente HTTP:

axios.defaults.withCredentials = true;

Finalmente, asegúrate de que la configuración del dominio de la cookie de sesión de tu aplicación admita cualquier subdominio de tu dominio raíz. Puedes lograr esto agregando un punto . al principio del dominio en el archivo de configuración config/session.php de tu aplicación:

'domain' => '.domain.com',

Autenticación

Protección CSRF

Para autenticar tu SPA, la página de "inicio de sesión" de tu SPA debe realizar primero una solicitud al punto final /sanctum/csrf-cookie para inicializar la protección CSRF para la aplicación:

axios.get('/sanctum/csrf-cookie').then(response => {
// Iniciar sesión...
});

Durante esta solicitud, Laravel establecerá una cookie XSRF-TOKEN que contiene el token CSRF actual. Este token debe pasarse en la cabecera X-XSRF-TOKEN en solicitudes subsiguientes, lo cual algunas bibliotecas de clientes HTTP, como Axios y Angular HttpClient, harán automáticamente por ti. Si tu biblioteca HTTP de JavaScript no establece el valor por ti, deberás configurar manualmente la cabecera X-XSRF-TOKEN para que coincida con el valor de la cookie XSRF-TOKEN que establece esta ruta.

Inicio de Sesión

Una vez que se ha inicializado la protección CSRF, debes realizar una solicitud POST a la ruta /login de tu aplicación Laravel. Esta ruta /login se puede implementar manualmente o utilizando un paquete de autenticación sin cabeza como Laravel Fortify.

Si la solicitud de inicio de sesión es exitosa, estarás autenticado y las solicitudes subsiguientes a las rutas de tu aplicación se autenticarán automáticamente mediante la cookie de sesión que la aplicación Laravel emitió a tu cliente. Además, dado que tu aplicación ya realizó una solicitud a la ruta /sanctum/csrf-cookie, las solicitudes subsiguientes deben recibir automáticamente protección CSRF siempre que tu cliente HTTP de JavaScript envíe el valor de la cookie XSRF-TOKEN en la cabecera X-XSRF-TOKEN.

Por supuesto, si la sesión de tu usuario expira debido a la falta de actividad, las solicitudes subsiguientes a la aplicación Laravel pueden recibir una respuesta de error HTTP 401 o 419. En este caso, debes redirigir al usuario a la página de inicio de sesión de tu SPA.

Advertencia Eres libre de escribir tu propio punto final /login; sin embargo, asegúrate de que autentique al usuario utilizando los servicios de autenticación basados en sesiones que proporciona Laravel de forma estándar. Normalmente, esto significa usar la guarda de autenticación web.

Protección de Rutas

Para proteger rutas para que todas las solicitudes entrantes deban estar autenticadas, debes adjuntar la guarda de autenticación sanctum a tus rutas API dentro de tu archivo routes/api.php. Esta guarda garantizará que las solicitudes entrantes estén autenticadas como solicitudes autenticadas con estado desde tu SPA o contengan una cabecera de token de API válida si la solicitud es de un tercero:

use Illuminate\Http\Request;
 
Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
return $request->user();
});

Autorización de Canales de Transmisión Privados

Si tu SPA necesita autenticarse con canales de difusión privados/presenciales, debes colocar la llamada al método Broadcast::routes dentro de tu archivo routes/api.php:

Broadcast::routes(['middleware' => ['auth:sanctum']]);

A continuación, para que las solicitudes de autorización de Pusher tengan éxito, deberás proporcionar un authorizer personalizado de Pusher al inicializar Laravel Echo. Esto permite que tu aplicación configure Pusher para usar la instancia axios que está configurada correctamente para solicitudes entre dominios:

window.Echo = new Echo({
broadcaster: "pusher",
cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER,
encrypted: true,
key: import.meta.env.VITE_PUSHER_APP_KEY,
authorizer: (channel, options) => {
return {
authorize: (socketId, callback) => {
axios.post('/api/broadcasting/auth', {
socket_id: socketId,
channel_name: channel.name
})
.then(response => {
callback(false, response.data);
})
.catch(error => {
callback(true, error);
});
}
};
},
})

Autenticación de Aplicaciones Móviles

También puedes utilizar tokens de Sanctum para autenticar las solicitudes de tu aplicación móvil a tu API. El proceso para autenticar solicitudes de aplicaciones móviles es similar a autenticar solicitudes de API de terceros; sin embargo, hay pequeñas diferencias en cómo emitir los tokens de API.

Emisión de Tokens de API

Para empezar, crea una ruta que acepte el correo electrónico/nombre de usuario, la contraseña y el nombre del dispositivo del usuario, y luego intercambie esas credenciales por un nuevo token de Sanctum. El "nombre del dispositivo" proporcionado a este punto final es con fines informativos y puede ser cualquier valor que desees. En general, el valor del nombre del dispositivo debería ser un nombre que el usuario reconocería, como "iPhone 12 de Nuno".

Normalmente, harás una solicitud al punto final del token desde la pantalla de "inicio de sesión" de tu aplicación móvil. El punto final devolverá el token de API en texto plano, que luego se puede almacenar en el dispositivo móvil y utilizar para realizar solicitudes adicionales a la API:

use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\ValidationException;
 
Route::post('/sanctum/token', function (Request $request) {
$request->validate([
'email' => 'required|email',
'password' => 'required',
'device_name' => 'required',
]);
 
$user = User::where('email', $request->email)->first();
 
if (! $user || ! Hash::check($request->password, $user->password)) {
throw ValidationException::withMessages([
'email' => ['The provided credentials are incorrect.'],
]);
}
 
return $user->createToken($request->device_name)->plainTextToken;
});

Cuando la aplicación móvil utiliza el token para realizar una solicitud a tu aplicación, debe pasar el token en la cabecera Authorization como un token Bearer.

Nota Cuando emites tokens para una aplicación móvil, también eres libre de especificar habilidades del token.

Protección de Rutas

Como se documentó anteriormente, puedes proteger rutas para que todas las solicitudes entrantes deben estar autenticadas adjuntando la guarda de autenticación sanctum a las rutas:

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

Revocación de Tokens

Para permitir a los usuarios revocar tokens de API emitidos a dispositivos móviles, puedes enumerarlos por nombre, junto con un botón "Revocar", dentro de la sección "configuración de la cuenta" de la interfaz de usuario de tu aplicación web. Cuando el usuario hace clic en el botón "Revocar", puedes eliminar el token de la base de datos. Recuerda que puedes acceder a los tokens de API de un usuario mediante la relación tokens proporcionada por el rasgo Laravel\Sanctum\HasApiTokens:

// Revocar todos los tokens...
$user->tokens()->delete();
 
// Revocar un token específico...
$user->tokens()->where('id', $tokenId)->delete();

Pruebas

Durante las pruebas, el método Sanctum::actingAs se puede utilizar para autenticar a un usuario y especificar qué habilidades se deben otorgar a su token:

use App\Models\User;
use Laravel\Sanctum\Sanctum;
 
public function test_task_list_can_be_retrieved(): void
{
Sanctum::actingAs(
User::factory()->create(),
['view-tasks']
);
 
$response = $this->get('/api/task');
 
$response->assertOk();
}

Si deseas otorgar todas las habilidades al token, debes incluir * en la lista de habilidades proporcionada al método actingAs:

Sanctum::actingAs(
User::factory()->create(),
['*']
);