Laravel 12 REST API with Sanctum Authentication


Laravel 12 REST API with Sanctum Authentication

Download

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.

  1. Install Laravel 12 App and Sanctum API
  2. Add HasApiTokens Trait in User Model
  3. Create API Response Trait
  4. Create LoginRegister Controller
  5. Create Product Resource, Model with Migration and API Resource Controller
  6. Define API Routes in routes/api.php
  7. 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.

Postman Header Accept JSON

List of API Endpoints and Methods

Below is a list of our API endpoints with their corresponding HTTP methods.

MethodEndpointAuthDescription
POST/api/registerNoRegister user and receive token
POST/api/loginNoLogin and receive token
POST/api/logoutYesInvalidate token
GET/api/productsNoGet all products
GET/api/products/{id}NoGet a specific product
POST/api/productsYesCreate a new product
PATCH/api/products/{id}YesUpdate product
DELETE/api/products/{id}YesDelete 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.

User Registration API

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.

User Login API

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.

Add Bearer Token in Authorization

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.

Create Product API

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.

Show All Products API

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.

Show Single Product API

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.

Update Product API

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.

Delete Product API

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!

Download

Facebook Official Page: All PHP Tricks

Twitter Official Page: All PHP Tricks

Article By
Javed Ur Rehman is a passionate blogger and web developer, he loves to share web development tutorials and blogging tips. He usually writes about HTML, CSS, JavaScript, Jquery, Ajax, PHP and MySQL.

Leave a Reply

Your email address will not be published. Required fields are marked *