In this tutorial, you will build a complete REST API with token-based authentication using Laravel 12 and Laravel Sanctum. We will create endpoints for user registration, login, and a protected resource (posts).
composer create-project laravel/laravel laravel-api
cd laravel-api
composer require laravel/sanctum
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
php artisan migrate
Open app/Models/User.php and add the HasApiTokens trait:
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
}
php artisan make:model Post -mc
Open the generated migration and define the posts table:
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
$table->string('title');
$table->text('body');
$table->timestamps();
});
php artisan migrate
php artisan make:controller Api/AuthController
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
class AuthController extends Controller
{
public function register(Request $request): JsonResponse
{
$data = $request->validate([
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users',
'password' => 'required|string|min:8|confirmed',
]);
$user = User::create([...$data, 'password' => Hash::make($data['password'])]);
$token = $user->createToken('api-token')->plainTextToken;
return response()->json(['token' => $token, 'user' => $user], 201);
}
public function login(Request $request): JsonResponse
{
$request->validate([
'email' => 'required|email',
'password' => 'required',
]);
$user = User::where('email', $request->email)->first();
if (! $user || ! Hash::check($request->password, $user->password)) {
return response()->json(['message' => 'Invalid credentials'], 401);
}
$token = $user->createToken('api-token')->plainTextToken;
return response()->json(['token' => $token, 'user' => $user]);
}
public function logout(Request $request): JsonResponse
{
$request->user()->currentAccessToken()->delete();
return response()->json(['message' => 'Logged out successfully']);
}
}
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\Post;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class PostController extends Controller
{
public function index(Request $request): JsonResponse
{
$posts = $request->user()->posts()->latest()->paginate(10);
return response()->json($posts);
}
public function store(Request $request): JsonResponse
{
$data = $request->validate([
'title' => 'required|string|max:255',
'body' => 'required|string',
]);
$post = $request->user()->posts()->create($data);
return response()->json($post, 201);
}
public function show(Post $post): JsonResponse
{
$this->authorize('view', $post);
return response()->json($post);
}
public function update(Request $request, Post $post): JsonResponse
{
$this->authorize('update', $post);
$data = $request->validate([
'title' => 'sometimes|string|max:255',
'body' => 'sometimes|string',
]);
$post->update($data);
return response()->json($post);
}
public function destroy(Post $post): JsonResponse
{
$this->authorize('delete', $post);
$post->delete();
return response()->json(null, 204);
}
}
Open routes/api.php and add the routes:
use App\Http\Controllers\Api\AuthController;
use App\Http\Controllers\Api\PostController;
// Public routes
Route::post('/register', [AuthController::class, 'register']);
Route::post('/login', [AuthController::class, 'login']);
// Protected routes
Route::middleware('auth:sanctum')->group(function () {
Route::post('/logout', [AuthController::class, 'logout']);
Route::apiResource('posts', PostController::class);
});
# Register
curl -X POST http://localhost:8000/api/register \
-H "Content-Type: application/json" \
-d '{"name":"Alice","email":"[email protected]","password":"password","password_confirmation":"password"}'
# Login — save the returned token
curl -X POST http://localhost:8000/api/login \
-H "Content-Type: application/json" \
-d '{"email":"[email protected]","password":"password"}'
# Create a post (use token from login)
curl -X POST http://localhost:8000/api/posts \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"title":"Hello","body":"World"}'
# List posts
curl http://localhost:8000/api/posts \
-H "Authorization: Bearer YOUR_TOKEN"
All Comments