Laravel 12 REST API with Sanctum Authentication

In this tutorial, we will walk you through creating a Laravel 12 REST API with Sanctum authentication. You will learn how to build a complete Laravel 12 REST API step by step using a simple and beginner-friendly approach.
Laravel continues to be one of the most popular PHP frameworks for building powerful and scalable APIs. In this tutorial, we’ll guide you through the essential steps to develop a modern Laravel 12 REST API with ease and clarity.
Readers Also Read: Laravel 12 User Registration and Login
Steps to Create a Laravel 12 REST API Using Sanctum Authentication
Follow the simple, step-by-step guide below to create a Laravel 12 REST API with Sanctum authentication using a practical example application.
- Install Laravel 12 App and Sanctum API
- Add HasApiTokens Trait in User Model
- Create API Response Trait
- Create LoginRegister Controller
- Create Product Resource, Model with Migration and API Resource Controller
- Define API Routes in routes/api.php
- Test API on Postman
Readers Also Read: Laravel 12 CRUD Application Tutorial
Step 1. Install Laravel 12 App and Sanctum API
If you don’t have Laravel 12 installed, start by creating a new Laravel 12 application named laravel-12-api-sanctum
using the following command:
composer create-project --prefer-dist laravel/laravel laravel-12-api-sanctum
cd laravel-12-api-sanctum
Enable api.php
and install Sanctum in Laravel 12 by running the following command:
php artisan install:api
Step 2. Add HasApiTokens Trait in User Model
Add the following in your User model \app\Models\User.php
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
....
Step 3. Create API Response Trait
First, create the API Response trait. Run the following command in your terminal to generate the ApiResponseTrait.php
file inside the Traits
directory:
php artisan make:trait Traits\ApiResponseTrait
Next, add the following code to the file.
<?php
namespace App\Traits;
use Illuminate\Http\JsonResponse;
trait ApiResponseTrait
{
protected function successResponse($data = null, $message = 'Success', $code = 200): JsonResponse
{
return response()->json([
'success' => true,
'message' => $message,
'data' => $data,
], $code);
}
protected function errorResponse($message = 'Error', $code = 400, $errors = null): JsonResponse
{
return response()->json([
'success' => false,
'message' => $message,
'errors' => $errors,
], $code);
}
}
Step 4. Create LoginRegister Controller
Now we need to create the LoginRegister controller. Simply run the command below in your terminal.
php artisan make:controller Api\LoginRegisterController
Copy and paste the following code in app/Http/Controllers/Api/LoginRegisterController.php
<?php
namespace App\Http\Controllers\Api;
use App\Models\User;
use App\Http\Controllers\Controller;
use App\Traits\ApiResponseTrait;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Hash;
class LoginRegisterController extends Controller
{
use ApiResponseTrait;
/**
* Register a new user.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function register(Request $request)
{
$validator = Validator::make($request->all(), [
'name' => 'required|string|max:255',
'email' => 'required|string|email:rfc,dns|unique:users,email|max:250',
'password' => 'required|string|min:6|confirmed',
]);
if ($validator->fails()) {
return $this->errorResponse('Validation Error!', 422, $validator->errors());
}
$user = User::create($request->all());
$data['token'] = $user->createToken($request->email)->plainTextToken;
$data['user'] = $user;
return $this->successResponse($data, 'User is registered successfully', 201);
}
/**
* Authenticate the user.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function login(Request $request)
{
$validator = Validator::make($request->all(), [
'email' => 'required|string|email',
'password' => 'required|string',
]);
if ($validator->fails()) {
return $this->errorResponse('Validation Error!', 422, $validator->errors());
}
// Check email exist
$user = User::where('email', $request->email)->first();
// Check password
if (! $user || ! Hash::check($request->password, $user->password)) {
return $this->errorResponse('Invalid credentials', 401);
}
$data['token'] = $user->createToken($request->email)->plainTextToken;
$data['user'] = $user;
return $this->successResponse($data, 'Login successful');
}
public function logout(Request $request)
{
$request->user()->currentAccessToken()->delete();
return $this->successResponse(null, 'Logged out successfully');
}
}
Step 5. Create Product Resource, Model with Migration and API Resource Controller
Simply run the commands below in your terminal.
php artisan make:model Product -mcr --api
php artisan make:resource ProductResource
Now, navigate to the database/migrations
directory and locate your product migration file named something like YYYY_MM_DD_TIMESTAMP_create_products_table.php
. Open it and replace its contents with the following code.
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('products', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->text('description')->nullable();
$table->decimal('price', 10, 2);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('products');
}
};
Run the migration:
php artisan migrate
Now, navigate to app/Models/Product.php
and update the Product model with the following code.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
protected $fillable = [
'name',
'description',
'price'
];
}
Now, go to app/Http/Resources/ProductResource.php
and update it with the following code.
<?php
namespace App\Http\Resources;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
class ProductResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @return array<string, mixed>
*/
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'name' => $this->name,
'description' => $this->description,
'price' => $this->price,
'created_at' => $this->created_at->format('d M, Y'),
];
}
}
And finally, go to app/Http/Controllers
and update the ProductController.php
file with the following code.
<?php
namespace App\Http\Controllers;
use App\Models\Product;
use App\Traits\ApiResponseTrait;
use App\Http\Resources\ProductResource;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
class ProductController extends Controller
{
use ApiResponseTrait;
/**
* Display a listing of the resource.
*/
public function index()
{
$products = ProductResource::collection(Product::latest()->get());
if (is_null($products->first())) {
return $this->errorResponse('No product found!', 404);
}
return $this->successResponse($products);
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
{
$validator = Validator::make($request->all(), [
'name' => 'required|string|max:255',
'description' => 'nullable|string',
'price' => 'required|numeric|min:0',
]);
if ($validator->fails()) {
return $this->errorResponse('Validation Error!', 422, $validator->errors());
}
$product = Product::create($request->all());
return $this->successResponse(new ProductResource($product), 'Product is created', 201);
}
/**
* Display the specified resource.
*/
public function show($id)
{
$product = Product::find($id);
if (! $product) {
return $this->errorResponse('Product not found', 404);
}
return $this->successResponse(new ProductResource($product));
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, $id)
{
$validator = Validator::make($request->all(), [
'name' => 'sometimes|required|string|max:255',
'description' => 'nullable|string',
'price' => 'sometimes|required|numeric|min:0',
]);
if ($validator->fails()) {
return $this->errorResponse('Validation Error!', 422, $validator->errors());
}
$product = Product::find($id);
if (! $product) {
return $this->errorResponse('Product not found', 404);
}
$product->update($request->all());
return $this->successResponse(new ProductResource($product), 'Product is updated');
}
/**
* Remove the specified resource from storage.
*/
public function destroy($id)
{
$product = Product::find($id);
if (! $product) {
return $this->errorResponse('Product not found', 404);
}
$product->delete();
return $this->successResponse(null, 'Product is deleted');
}
}
Step 6. Define API Routes in routes/api.php
Now, we need to define the API routes (endpoints) for user registration, login, logout, and product CRUD operations.
Simply copy and paste the code below into routes/api.php
.
<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\ProductController;
use App\Http\Controllers\Api\LoginRegisterController;
// Public routes of authtication
Route::controller(LoginRegisterController::class)->group(function() {
Route::post('/register', 'register');
Route::post('/login', 'login');
});
Route::apiResource('products', ProductController::class)->only(['index', 'show']);
// Protected routes of product and logout
Route::middleware('auth:sanctum')->group(function () {
Route::post('/logout', [LoginRegisterController::class, 'logout']);
Route::apiResource('products', ProductController::class)->except(['index', 'show']);
});
Step 7. Test API on Postman
It’s time to run the development server and test the Laravel 12 REST APIs built using Sanctum authentication.
Run the below command in terminal.
php artisan serve
Make sure to add Accept: application/json
in the header of all API requests, as shown in the screenshot below.

List of API Endpoints and Methods
Below is a list of our API endpoints with their corresponding HTTP methods.
Method | Endpoint | Auth | Description |
---|---|---|---|
POST | /api/register | No | Register user and receive token |
POST | /api/login | No | Login and receive token |
POST | /api/logout | Yes | Invalidate token |
GET | /api/products | No | Get all products |
GET | /api/products/{id} | No | Get a specific product |
POST | /api/products | Yes | Create a new product |
PATCH | /api/products/{id} | Yes | Update product |
DELETE | /api/products/{id} | Yes | Delete a product |
Now, open your Postman application, click on the New button, and select HTTP.
1) User Registration API URL: http://127.0.0.1:8000/api/register
This is a public route. Enter the required fields and click the Send button to get a response from the Laravel user registration API. The response will appear in the Body section, as shown in the screenshot below.

Note: In the data
object, a token
is generated, which will be used to access the protected routes.
Once the user is registered, you can log in anytime using the same credentials via the login route.
2) User Login API URL: http://127.0.0.1:8000/api/login
This is also a public route. Enter the required fields and click the Send button to get a response from the Laravel user login API. See the sample response in the screenshot below.

The login API also returns a token, which we’ll use to access the protected product routes for creating, reading, updating, and deleting a product.
Make sure to include the token with all protected routes by setting it in the Authorization
header: choose Bearer Token
as the Auth Type and paste the token into the token field, as shown in the screenshot below.

3) Create Product API URL: http://127.0.0.1:8000/api/products
This is a protected route. Add the token, enter the required fields, then click the Send button. See the sample response in the screenshot below.

4) Show All Products API URL: http://127.0.0.1:8000/api/product
This is a public route. Simply click the Send button and check the sample response in the screenshot below.

5) Show Single Product API URL: http://127.0.0.1:8000/api/products/{id}
This is a public route. Just pass the ID in the end of endpoint and click the Send button and refer to the sample response in the screenshot below.

6) Update Product API URL: http://127.0.0.1:8000/api/products/{id}
This is a protected route. Pass the ID in the end of endpoint and add the token, enter the required fields, then click the Send button and check the sample response in the screenshot below.

7) Delete Product API URL: http://127.0.0.1:8000/api/products/{id}
This is a protected route. Just pass the ID in the end of endpoint and add the token, click the Send button, and check the sample response in the screenshot below.

Conclusion
We hope you’ve now learned how to create a Laravel 12 REST API with Sanctum authentication by following the step-by-step guide above.
If you found this tutorial helpful, please share it with your friends and developer groups.
I spent several hours creating this tutorial. If you’d like to say thanks, consider liking my pages on Facebook, Twitter, and GitHub — and don’t forget to share it!
Facebook Official Page: All PHP Tricks
Twitter Official Page: All PHP Tricks