Laravel Sanctum API Authentication

Laravel Sanctum is a lightweight package for API authentication. It issues personal access tokens for mobile apps and third-party clients, and also supports cookie-based authentication for single-page apps on the same domain.

Setting Up Laravel Sanctum

php artisan install:api installs Sanctum and creates the personal_access_tokens table. Then add the HasApiTokens trait to your User model.

<?php
namespace App\Models;

use Illuminate\Foundation\Auth\User as Authenticatable;
use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable
{
    use HasApiTokens;
    // ...
}
(User model can now create and use API tokens)

Issuing Tokens on Login

The plain text token is shown only once. Sanctum stores only a hash of it in the database.

<?php
// routes/api.php
Route::post('/tokens', 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' => 'Invalid credentials.']);
    }

    $token = $user->createToken($request->device_name, ['orders:read']);
    return ['token' => $token->plainTextToken];
});
{"token":"3|kq9vP2xT8mLr0aZb6YcN1wHs4dJf7eUg5iQo"}

Protecting Routes With auth:sanctum

<?php
Route::middleware('auth:sanctum')->group(function () {
    Route::get('/user', fn (Request $request) => $request->user());
    Route::apiResource('orders', OrderController::class);
});

// Client request
// curl http://localhost:8000/api/user \
//   -H "Accept: application/json" \
//   -H "Authorization: Bearer 3|kq9vP2xT8mLr0aZb6YcN1wHs4dJf7eUg5iQo"
With token    -> {"id":1,"name":"Naeem","email":"naeem@example.com"}
Without token -> 401 {"message":"Unauthenticated."}

Token Abilities

Abilities work like scopes, limiting what a token may do.

<?php
if ($request->user()->tokenCan('orders:write')) {
    // create the order
} else {
    abort(403, 'Token lacks orders:write ability');
}
403 Token lacks orders:write ability

Revoking Tokens

<?php
// Log out the current device
$request->user()->currentAccessToken()->delete();

// Log out everywhere
$request->user()->tokens()->delete();
{"message":"Logged out"}

SPA Authentication

For a Vue or React SPA on the same top-level domain, Sanctum can use Laravel session cookies instead of tokens. Request /sanctum/csrf-cookie first, log in via a normal POST, and configure SANCTUM_STATEFUL_DOMAINS. This avoids storing tokens in localStorage.

Frequently asked questions

What is the difference between Sanctum and Passport?

Sanctum is simple token and SPA authentication. Passport is a full OAuth2 server, needed only if third parties must obtain tokens via OAuth flows.

Do Sanctum tokens expire?

Not by default. Set the expiration value (in minutes) in config/sanctum.php, or pass an expiry date to createToken.

Where should a mobile app store the Sanctum token?

In secure platform storage such as the iOS Keychain or Android Keystore, and send it in the Authorization: Bearer header.