APIs (Application Programming Interfaces) allow applications to communicate with each other. Laravel provides multiple ways to build APIs, and Sanctum is the most efficient method for token-based authentication. In this tutorial, we’ll build a secure REST API in Laravel 12 using Sanctum with authentication, CRUD operations, and middleware protection.
First, install Laravel 12 using Composer:
composer create-project laravel/laravel laravel-sanctum-api
Navigate to the project folder:
cd laravel-sanctum-api
Run the following command to install Sanctum:
composer require laravel/sanctum
Publish the configuration file:
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
Run migrations:
php artisan migrate
Enable Sanctum middleware in app/Http/Kernel.php:
use Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful;
protected $middlewareGroups = [
'api' => [
EnsureFrontendRequestsAreStateful::class,
'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
];
Next, add the HasApiTokens trait in the User model:
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
}
php artisan make:controller AuthController
Now, define the register, login, and logout methods in app/Http/Controllers/AuthController.php:
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\ValidationException;
class AuthController extends Controller
{
// User Registration
public function register(Request $request)
{
$request->validate([
'name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|min:6'
]);
$user = User::create([
'name' => $request->name,
'email' => $request->email,
'password' => Hash::make($request->password),
]);
return response()->json([
'token' => $user->createToken('api-token')->plainTextToken,
'user' => $user,
], 201);
}
// User Login
public function login(Request $request)
{
$request->validate([
'email' => 'required|email',
'password' => 'required'
]);
$user = User::where('email', $request->email)->first();
if (!$user || !Hash::check($request->password, $user->password)) {
throw ValidationException::withMessages([
'email' => ['Invalid credentials.'],
]);
}
return response()->json([
'token' => $user->createToken('api-token')->plainTextToken,
'user' => $user,
], 200);
}
// User Logout
public function logout(Request $request)
{
$request->user()->tokens()->delete();
return response()->json(['message' => 'Logged out successfully'], 200);
}
}
Define API routes in routes/api.php:
use App\Http\Controllers\AuthController;
use App\Http\Controllers\ArticleController;
use Illuminate\Support\Facades\Route;
Route::post('/register', [AuthController::class, 'register']);
Route::post('/login', [AuthController::class, 'login']);
Route::middleware('auth:sanctum')->group(function () {
Route::post('/logout', [AuthController::class, 'logout']);
Route::apiResource('/articles', ArticleController::class);
});
php artisan make:model Article -mcr
Define the Article model in app/Models/Article.php:
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Article extends Model
{
use HasFactory;
protected $fillable = ['title', 'content', 'user_id'];
}
Run the migration:
php artisan migrate
Implement CRUD Operations in ArticleController
namespace App\Http\Controllers;
use App\Models\Article;
use Illuminate\Http\Request;
class ArticleController extends Controller
{
// Fetch all articles
public function index()
{
return response()->json(Article::all());
}
// Create a new article
public function store(Request $request)
{
$request->validate([
'title' => 'required|string|max:255',
'content' => 'required',
]);
$article = Article::create([
'title' => $request->title,
'content' => $request->content,
'user_id' => $request->user()->id,
]);
return response()->json($article, 201);
}
// Get single article
public function show(Article $article)
{
return response()->json($article);
}
// Update an article
public function update(Request $request, Article $article)
{
$this->authorize('update', $article);
$article->update($request->only(['title', 'content']));
return response()->json($article);
}
// Delete an article
public function destroy(Article $article)
{
$this->authorize('delete', $article);
$article->delete();
return response()->json(['message' => 'Article deleted'], 200);
}
}
Now, you can test your API in Postman or any API client:
POST /api/register
POST /api/login
Authorization: Bearer your_token
)POST /api/articles
GET /api/articles
GET /api/articles/{id}
PUT /api/articles/{id}
DELETE /api/articles/{id}
POST /api/logout
In this tutorial, we successfully built a secure REST API in Laravel 12 using Sanctum for authentication. We implemented user registration, login, logout, and CRUD operations for articles. This foundation can be extended further with features like role-based access, pagination, and file uploads.