Saltar al contenido principal

Qué es Sanctum

Laravel Sanctum es un paquete de autenticación ligero pensado para SPAs (single page applications), apps móviles y APIs sencillas. Puedes emitir y gestionar varios API tokens por usuario sin necesidad de dominar OAuth. Sanctum cubre dos casos de uso:
Modo de autenticaciónMecanismoUso típico
API tokensCabecera Authorization: Bearer <token>Apps móviles, integraciones de terceros
SPACookie de sesión + protección CSRFFrontend propio (Vue/React, etc.)
Si tu SPA llama a la API que tú mismo controlas, usa el modo SPA. Si la API la consumen apps móviles o terceros, usa API tokens. Puedes usar uno solo o los dos.

Sanctum frente a Passport

SanctumPassport
ComplejidadSencilloOAuth2 completo
Ideal paraSPA y apps móviles propiasSer proveedor OAuth para terceros
Tipo de tokenPersonal access tokensAccess tokens OAuth2
Si necesitas actuar como proveedor OAuth2 hacia otros, elige Passport. Para la mayoría de aplicaciones, Sanctum es suficiente.

Instalación y configuración

Instalación

Con el comando Artisan install:api se instala Sanctum.
php artisan install:api
Este comando:
  • Instala el paquete laravel/sanctum.
  • Publica la migración de la tabla personal_access_tokens.
  • Ejecuta la migración.

Añadir el trait HasApiTokens

Añade el trait HasApiTokens al modelo User.
// app/Models/User.php

use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;
}
Con esto puedes usar métodos como $user->createToken() o $user->tokens.

Autenticación con API tokens

Flujo de tokens

Emitir un token

Usa createToken(). La propiedad plainTextToken contiene el valor en texto plano. Ese valor no se guarda en la base de datos, por lo que debes devolvérselo al usuario inmediatamente.
use Illuminate\Http\Request;

Route::post('/tokens/create', function (Request $request) {
    $token = $request->user()->createToken($request->token_name);

    return ['token' => $token->plainTextToken];
})->middleware('auth');
En la base de datos se guarda el token con hash SHA-256.

Configurar scopes (abilities)

Puedes asignar abilities (scopes) al token para restringir las operaciones que permite.
// Token con scopes
$token = $user->createToken('mobile-app', ['server:update', 'server:read']);

return $token->plainTextToken;
Al procesar la petición, comprueba los scopes.
if ($request->user()->tokenCan('server:update')) {
    // Ejecutar la operación de actualización
}

if ($request->user()->tokenCant('server:update')) {
    abort(403);
}

Comprobar scopes con middleware

Registra el alias del middleware en bootstrap/app.php.
use Laravel\Sanctum\Http\Middleware\CheckAbilities;
use Laravel\Sanctum\Http\Middleware\CheckForAnyAbility;

->withMiddleware(function (Middleware $middleware): void {
    $middleware->alias([
        'abilities' => CheckAbilities::class,  // Todas las abilities
        'ability'   => CheckForAnyAbility::class, // Alguna ability
    ]);
})
Aplica el middleware a las rutas.
// Solo tokens con check-status y place-orders a la vez
Route::get('/orders', function () {
    // ...
})->middleware(['auth:sanctum', 'abilities:check-status,place-orders']);

// Tokens con check-status o place-orders
Route::get('/orders', function () {
    // ...
})->middleware(['auth:sanctum', 'ability:check-status,place-orders']);

Caducidad de los tokens

Por defecto los tokens de Sanctum no expiran. Configura la caducidad en minutos con expiration en config/sanctum.php.
// config/sanctum.php
'expiration' => 525600, // 365 días (en minutos)
También puedes indicar una caducidad por token.
$token = $user->createToken(
    'token-name',
    ['*'],
    now()->addWeeks(1) // Caduca en 1 semana
)->plainTextToken;
Con caducidad activada, conviene programar la limpieza de tokens expirados.
use Illuminate\Support\Facades\Schedule;

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

Revocar tokens

// Eliminar todos los tokens
$user->tokens()->delete();

// Eliminar el token de la petición actual
$request->user()->currentAccessToken()->delete();

// Eliminar un token concreto
$user->tokens()->where('id', $tokenId)->delete();

Autenticación SPA

La autenticación SPA usa cookies de sesión, así que no necesitas emitir ni gestionar tokens. Es ideal para tu propio frontend (Vue, React, Next.js…) que consume tu API.
Para usar la autenticación SPA, el SPA y la API deben compartir dominio de nivel superior (los subdominios pueden ser distintos). Además, las peticiones deben incluir Accept: application/json y las cabeceras Referer u Origin.

Habilitar el middleware de Sanctum

Activa statefulApi() en bootstrap/app.php.
->withMiddleware(function (Middleware $middleware): void {
    $middleware->statefulApi();
})

Configurar los dominios first-party

Indica el dominio del SPA en la opción stateful de config/sanctum.php.
// config/sanctum.php
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
    '%s%s',
    'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1',
    Sanctum::currentApplicationUrlWithPort()
))),

Configuración de CORS

Si tu API se consume desde otro subdominio, hay que configurar CORS.
php artisan config:publish cors
En config/cors.php pon supports_credentials a true.
// config/cors.php
'supports_credentials' => true,
También en axios del frontend.
// resources/js/bootstrap.js
axios.defaults.withCredentials = true;
axios.defaults.withXSRFToken = true;
No olvides configurar el dominio de la cookie de sesión.
// config/session.php
'domain' => '.example.com', // Con el punto inicial

Flujo de autenticación desde el SPA

1

Obtener la cookie CSRF

Antes del login, llama a /sanctum/csrf-cookie para inicializar la protección CSRF.
await axios.get('/sanctum/csrf-cookie');
2

Enviar la petición de login

POST al endpoint /login.
await axios.post('/login', {
    email: '[email protected]',
    password: 'password',
});
3

Enviar peticiones autenticadas

Las peticiones posteriores se autentican automáticamente con la cookie.
const response = await axios.get('/api/user');
console.log(response.data); // Datos del usuario autenticado

Proteger rutas autenticadas

Aplica auth:sanctum a la ruta. Las peticiones no autenticadas reciben 401 Unauthorized. El mismo middleware sirve para API tokens y SPA.
use Illuminate\Http\Request;

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

// Grupo de rutas
Route::middleware('auth:sanctum')->group(function () {
    Route::get('/profile', [ProfileController::class, 'show']);
    Route::put('/profile', [ProfileController::class, 'update']);
    Route::get('/posts', [PostController::class, 'index']);
});

Ejemplo práctico: API de login que devuelve tokens

Ejemplo de autenticación con API tokens para una app móvil.
1

Crear el endpoint de login

// routes/api.php

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', 'string'],
    ]);

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

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

    return response()->json([
        'token' => $user->createToken($request->device_name)->plainTextToken,
    ]);
});
2

Crear las rutas autenticadas

// routes/api.php

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

    // Cierra sesión revocando el token actual
    Route::post('/logout', function (Request $request) {
        $request->user()->currentAccessToken()->delete();

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

    // Cierra sesión en todos los dispositivos
    Route::post('/logout/all', function (Request $request) {
        $request->user()->tokens()->delete();

        return response()->json(['message' => 'Sesión cerrada en todos los dispositivos.']);
    });
});
3

Consumirlo desde el cliente

// Login
const { data } = await axios.post('/api/sanctum/token', {
    email: '[email protected]',
    password: 'password',
    device_name: 'My iPhone',
});

const token = data.token;

// Peticiones autenticadas
const response = await axios.get('/api/user', {
    headers: {
        Authorization: `Bearer ${token}`,
    },
});

Pruebas

En los tests de Sanctum utiliza Sanctum::actingAs() para autenticar a un usuario y asignar abilities.
use App\Models\User;
use Laravel\Sanctum\Sanctum;

test('se puede obtener el listado de tareas', function () {
    Sanctum::actingAs(
        User::factory()->create(),
        ['view-tasks']
    );

    $response = $this->get('/api/tasks');

    $response->assertOk();
});

test('un token con todas las abilities puede acceder', function () {
    Sanctum::actingAs(
        User::factory()->create(),
        ['*']
    );

    $response = $this->get('/api/tasks');

    $response->assertOk();
});

Resumen

# Instalar Sanctum y ejecutar migraciones
php artisan install:api
Añade HasApiTokens al modelo User:
use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;
}
// Emitir token
$token = $user->createToken('token-name')->plainTextToken;

// Emitir token con scopes
$token = $user->createToken('token-name', ['read', 'write'])->plainTextToken;

// Comprobar scope
$user->tokenCan('read');   // true/false
$user->tokenCant('write'); // true/false

// Revocar
$user->tokens()->delete();                        // Todos
$request->user()->currentAccessToken()->delete(); // El actual
$user->tokens()->where('id', $id)->delete();      // Uno concreto
  • API tokens: apps móviles, terceros, CLI… clientes sin sesión.
  • Autenticación SPA: tu propio frontend Vue/React/Next.js sobre el mismo dominio (o subdominio). Más seguro y sin gestión de tokens.
Última modificación el 13 de julio de 2026