Vai al contenuto principale

Cos’è Sanctum

Laravel Sanctum è un pacchetto di autenticazione leggero per SPA, applicazioni mobili e API semplici. Senza conoscenze approfondite di OAuth puoi emettere e gestire più API token per utente. Sanctum risolve due problemi.
ModalitàMeccanismoUso
Autenticazione API tokenHeader Authorization: Bearer <token>App mobili, integrazioni di terze parti
Autenticazione SPACookie di sessione + protezione CSRFFrontend proprie (Vue/React, ecc.)
Per API chiamate dalla tua SPA usa l’autenticazione SPA. Per app mobili o integrazioni terze usa l’autenticazione con API token. Puoi usarne solo una.

Quando usare Passport

SanctumPassport
ComplessitàSempliceOAuth2 completo
UsoSPA/app mobili proprieProvider OAuth per app esterne
Tipo di tokenPersonal access tokenOAuth2 access token
Se devi essere un provider OAuth2 per servizi esterni, scegli Passport; per il resto Sanctum è sufficiente.

Installazione e configurazione

Installazione

php artisan install:api
Installa laravel/sanctum, pubblica la migration di personal_access_tokens ed esegue le migration.

Trait HasApiTokens

Aggiungi il trait a User.
use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;
}
Ora hai $user->createToken() e $user->tokens.

Autenticazione con API token

Flusso

Emettere un token

createToken() restituisce plainTextToken. Il token in chiaro non viene salvato: restituiscilo subito al client.
use Illuminate\Http\Request;

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

    return ['token' => $token->plainTextToken];
})->middleware('auth');
Nel DB è salvato con hash SHA-256.

Scope (abilities)

$token = $user->createToken('mobile-app', ['server:update', 'server:read']);

return $token->plainTextToken;
Verifica gli scope:
if ($request->user()->tokenCan('server:update')) {
    // Aggiorna
}

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

Middleware per scope

In 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,
        'ability'   => CheckForAnyAbility::class,
    ]);
})
Route::get('/orders', function () {
    // ...
})->middleware(['auth:sanctum', 'abilities:check-status,place-orders']);

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

Scadenza dei token

Di default nessuna scadenza. In config/sanctum.php expiration in minuti.
'expiration' => 525600, // 365 giorni
Per token:
$token = $user->createToken(
    'token-name',
    ['*'],
    now()->addWeeks(1)
)->plainTextToken;
Prune periodico:
use Illuminate\Support\Facades\Schedule;

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

Revocare token

$user->tokens()->delete();

$request->user()->currentAccessToken()->delete();

$user->tokens()->where('id', $tokenId)->delete();

Autenticazione SPA

Con cookie di sessione, senza gestione token. Ideale per frontend proprie.
SPA e API devono condividere lo stesso dominio (i sottodomini possono differire). Le richieste devono includere Accept: application/json e Referer o Origin.

Attiva il middleware Sanctum

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

Domini first-party

'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
    '%s%s',
    'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1',
    Sanctum::currentApplicationUrlWithPort()
))),

CORS

php artisan config:publish cors
'supports_credentials' => true,
Frontend axios:
axios.defaults.withCredentials = true;
axios.defaults.withXSRFToken = true;
Sessione cookie:
'domain' => '.example.com',

Flusso di login SPA

1

Ottieni il cookie CSRF

await axios.get('/sanctum/csrf-cookie');
2

Login

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

Richieste autenticate

const response = await axios.get('/api/user');
console.log(response.data);

Protezione delle route

Applica auth:sanctum.
use Illuminate\Http\Request;

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

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

Esempio: API di login e restituzione del token

1

Endpoint di login

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' => ['Credenziali non valide.'],
        ]);
    }

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

Route autenticate

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

    Route::post('/logout', function (Request $request) {
        $request->user()->currentAccessToken()->delete();

        return response()->json(['message' => 'Logout effettuato.']);
    });

    Route::post('/logout/all', function (Request $request) {
        $request->user()->tokens()->delete();

        return response()->json(['message' => 'Logout da tutti i dispositivi.']);
    });
});
3

Chiamate dal client

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

const token = data.token;

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

Test

Con Sanctum::actingAs() autentichi e definisci gli scope.
use App\Models\User;
use Laravel\Sanctum\Sanctum;

test('è possibile ottenere la lista dei task', function () {
    Sanctum::actingAs(
        User::factory()->create(),
        ['view-tasks']
    );

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

    $response->assertOk();
});

test('token con tutte le abilities', function () {
    Sanctum::actingAs(
        User::factory()->create(),
        ['*']
    );

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

    $response->assertOk();
});

php artisan install:api
use Laravel\Sanctum\HasApiTokens;

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

$user->tokenCan('read');
$user->tokenCant('write');

$user->tokens()->delete();
$request->user()->currentAccessToken()->delete();
$user->tokens()->where('id', $id)->delete();
  • API token: client senza sessione (mobile, terze parti, CLI).
  • SPA: frontend Vue/React/Next.js sullo stesso dominio. Più sicura, no token da gestire.
Ultima modifica il 13 luglio 2026