Laravel Sanctum Setup Tutorial: Complete API Authentication Guide (2026)

Quick Setup: Laravel Sanctum in 5 steps Run composer require laravel/sanctum → publish config → php artisan migrate → add HasApiTokens to User model → protect routes with auth:sanctum middleware → issue tokens on login with $user->createToken('token-name')->plainTextToken.

Laravel Sanctum is the official, lightweight API authentication package built into Laravel. It handles token issuance, route protection, and token revocation with minimal setup — making it the right choice for almost every Laravel REST API and mobile backend.

This tutorial covers a complete Sanctum setup from scratch: installation, User model configuration, protected routes, a full AuthController, and how to make authenticated requests. All examples work with Laravel 12.

What is Laravel Sanctum?

Sanctum provides API token authentication using plain-text tokens stored in a personal_access_tokens database table. Unlike JWT, tokens aren't self-contained — each request does a quick database lookup to validate. The trade-off is instant, reliable token revocation.

FeatureSanctumPassportJWT (tymon)
Best forYour own APIOAuth2 / third-partyStateless / microservices
Token storageDatabaseDatabaseClient-side only
Setup complexitySimpleComplexMedium
Built into Laravel✅ Yes❌ No❌ No
Token revocation✅ Easy✅ Yes⚠️ Hard
SPA cookie auth✅ YesNoNo

For most Laravel REST APIs, Sanctum is the right choice. Use Passport only when you need a full OAuth2 server for third-party developers.

Step 1: Install Laravel Sanctum

On Laravel 11 and 12, Sanctum is included by default. For Laravel 10 and below, install it manually:

Terminal
# Laravel 10 and below — install manually composer require laravel/sanctum php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider" php artisan migrate
Laravel 11 / 12: Sanctum is already installed. Just run php artisan migrate if you haven't already — the personal_access_tokens table migration is included.

Step 2: Add HasApiTokens to the User Model

Add the HasApiTokens trait to your User model. This gives the model the createToken(), tokens(), and currentAccessToken() methods:

app/Models/User.php
<?php namespace App\Models; use Illuminate\Foundation\Auth\User as Authenticatable; use Laravel\Sanctum\HasApiTokens; class User extends Authenticatable { use HasApiTokens; // rest of your model... }

Step 3: Set Up API Routes

Define your public and protected routes in routes/api.php. The auth:sanctum middleware guards any route that requires a valid token:

routes/api.php
use App\Http\Controllers\Api\AuthController; use App\Http\Controllers\Api\UserController; Route::prefix('v1')->group(function () { // Public routes — no token required Route::prefix('auth')->group(function () { Route::post('register', [AuthController::class, 'register']); Route::post('login', [AuthController::class, 'login']); }); // Protected routes — valid Sanctum token required Route::middleware('auth:sanctum')->group(function () { Route::post('auth/logout', [AuthController::class, 'logout']); Route::get('auth/me', [AuthController::class, 'me']); Route::get('users', [UserController::class, 'index']); }); });

Step 4: Build the AuthController

This controller handles registration, login, logout, and the authenticated user endpoint. The key line is createToken()->plainTextToken — this generates and returns the token the client will store and send on future requests:

app/Http/Controllers/Api/AuthController.php
<?php namespace App\Http\Controllers\Api; use App\Http\Controllers\Controller; use App\Models\User; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Hash; class AuthController extends Controller { public function register(Request $request) { $request->validate([ 'name' => 'required|string|max:255', 'email' => 'required|email|unique:users', 'password' => 'required|min:8|confirmed', ]); $user = User::create([ 'name' => $request->name, 'email' => $request->email, 'password' => Hash::make($request->password), ]); $token = $user->createToken('auth_token')->plainTextToken; return response()->json([ 'user' => $user, 'token' => $token, ], 201); } public function login(Request $request) { $request->validate([ 'email' => 'required|email', 'password' => 'required', ]); if (! Auth::attempt($request->only('email', 'password'))) { return response()->json([ 'message' => 'Invalid credentials' ], 401); } $user = Auth::user(); $token = $user->createToken('auth_token')->plainTextToken; return response()->json([ 'user' => $user, 'token' => $token, ]); } public function logout(Request $request) { $request->user()->currentAccessToken()->delete(); return response()->json([ 'message' => 'Logged out successfully' ]); } public function me(Request $request) { return response()->json($request->user()); } }

Step 5: Make Authenticated Requests

After login, the client receives a plain-text token. Send it in the Authorization header as a Bearer token on every protected request:

HTTP Requests
# 1. Login — get your token POST /api/v1/auth/login Content-Type: application/json { "email": "user@example.com", "password": "yourpassword" } # Response { "user": { "id": 1, "name": "John", ... }, "token": "1|abc123yourtokenhere..." } # 2. Use the token on protected requests GET /api/v1/auth/me Authorization: Bearer 1|abc123yourtokenhere...
Token format: Sanctum tokens look like 1|randomstring. The number before the pipe is the token ID in the database. Always send the full string including the numeric prefix.

Token Abilities (Optional Scopes)

Sanctum supports token abilities — a simple alternative to OAuth scopes. You can restrict what each token is allowed to do:

Token abilities
// Issue a token with specific abilities $token = $user->createToken('mobile-app', ['read', 'write'])->plainTextToken; // Check ability in a controller if ($request->user()->tokenCan('write')) { // allowed } // Or enforce via middleware Route::middleware(['auth:sanctum', 'ability:write'])->group(function () { Route::post('posts', [PostController::class, 'store']); });

Revoking Tokens

Because tokens are stored in the database, revocation is instant. This is one of Sanctum's biggest advantages over JWT — no denylist needed, just delete the row:

Revocation options
// Revoke the current token (standard logout) $request->user()->currentAccessToken()->delete(); // Revoke all tokens — logout from every device $user->tokens()->delete(); // Revoke tokens by name $user->tokens()->where('name', 'mobile-app')->delete();

Setting Token Expiry

Set the expiration value in config/sanctum.php. The value is in minutes:

config/sanctum.php
// Expire tokens after 60 days 'expiration' => 60 * 24 * 60, // Tokens that never expire 'expiration' => null,

Common Issues & Fixes

401 Unauthenticated on every request

Make sure you're sending the token as Authorization: Bearer YOUR_TOKEN — not as a query parameter or cookie. Also confirm the HasApiTokens trait is on your User model and migrations have run.

CORS errors from a frontend SPA

Add your frontend URL to config/cors.php:

config/cors.php
'allowed_origins' => ['https://yourfrontend.com'], 'supports_credentials' => true,

Missing personal_access_tokens table

Run php artisan migrate and confirm the table exists in your database. On Laravel 11/12 this migration is included automatically.


Frequently Asked Questions

Does Laravel Sanctum use JWT tokens?

No. Sanctum uses plain-text tokens stored in your database, not JWT. JWT tokens are stateless and self-contained; Sanctum tokens require a database lookup on each request. The trade-off is that Sanctum tokens are much easier to revoke instantly. See the full breakdown in Laravel Sanctum vs JWT.

When should I use Sanctum vs Passport?

Use Sanctum when you're building an API for your own frontend — SPA or mobile app. Use Passport only when you need a full OAuth2 server to issue tokens to third-party developers. Passport is significantly more complex to set up and maintain.

Can I use Sanctum for SPA cookie authentication?

Yes — Sanctum also supports cookie-based SPA authentication using CSRF tokens. For a REST API or mobile backend, token-based authentication as shown in this tutorial is the standard approach.

Building a Laravel API?

I've built Sanctum authentication into production systems including payroll platforms, SaaS tools, and e-commerce APIs. Save time with a pre-built starter kit or get in touch for custom work.

Sanctum pre-configured · Auth, roles, pagination included · $19

About the Author

Kamruzzaman Polash — Software Engineer specialising in Laravel, REST APIs, and scalable backend systems. 10+ projects delivered for clients worldwide.