Laravel 10 REST API Authentication using Sanctum Tutorial

Laravel10, Sanctum is a popular package for API authentication in Laravel applications. It provides a simple and convenient way to implement token-based authentication for your RESTful APIs.

Token-Based Authentication: Sanctum uses tokens to authenticate API requests. It generates secure, random tokens that can be used to authenticate users and protect API routes. These tokens can be stored in cookies or sent with each request as API tokens.

Step 1: Install Laravel App

composer create-project laravel/laravel example-Sanctum

Step 2: Install Sanctum Package

composer require laravel/sanctum

After successfully install package, we need to publish configuration file with following command:

php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"

Run migration command,

php artisan migrate

app/Http/Kernel.php

....
  
    'api' => [
        \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
        'throttle:api',
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
    ],
      
    ....

Step 3: Sanctum Configuration

app/Models/User.php

<?php
  
    namespace App\Models;
      
    use Illuminate\Contracts\Auth\MustVerifyEmail;
    use Illuminate\Database\Eloquent\Factories\HasFactory;
    use Illuminate\Foundation\Auth\User as Authenticatable;
    use Illuminate\Notifications\Notifiable;
    use Laravel\Sanctum\HasApiTokens;
      
    class User extends Authenticatable
    {
        use HasFactory, Notifiable, HasApiTokens;
      
        /**
         * The attributes that are mass assignable.
         *
         * @var array
         */
        protected $fillable = [
            'name',
            'email',
            'password',
        ];
      
        /**
         * The attributes that should be hidden for arrays.
         *
         * @var array
         */
        protected $hidden = [
            'password',
            'remember_token',
        ];
      
        /**
         * The attributes that should be cast to native types.
         *
         * @var array
         */
        protected $casts = [
            'email_verified_at' => 'datetime',
        ];
    }

Step 4: Add Product Table and Model

 Run bellow command: 

php artisan make:migration create_products_table

After this command you will find one file in following path database/migrations and you have to put bellow code in your migration file for create products table.

<?php
  
  use Illuminate\Database\Migrations\Migration;
  use Illuminate\Database\Schema\Blueprint;
  use Illuminate\Support\Facades\Schema;
    
  return new class extends Migration
  {
      /**
       * Run the migrations.
       *
       * @return void
       */
      public function up(): void
      {
          Schema::create('products', function (Blueprint $table) {
              $table->id();
              $table->string('name');
              $table->text('detail');
              $table->timestamps();
          });
      }
    
      /**
       * Reverse the migrations.
       *
       * @return void
       */
      public function down(): void
      {
          Schema::dropIfExists('products');
      }
  };

After create migration we need to run above migration by following command:

php artisan migrate

app/Models/Product.php

<?php
  
    namespace App\Models;
      
    use Illuminate\Database\Eloquent\Factories\HasFactory;
    use Illuminate\Database\Eloquent\Model;
      
    class Product extends Model
    {
        use HasFactory;
      
        /**
         * The attributes that are mass assignable.
         *
         * @var array
         */
        protected $fillable = [
            'name', 'detail'
        ];

Step 5: Create API Routes

routes/api.php 

<?php
  
    use Illuminate\Http\Request;
    use Illuminate\Support\Facades\Route;
      
    use App\Http\Controllers\API\RegisterController;
    use App\Http\Controllers\API\ProductController;
      
    /*
    |--------------------------------------------------------------------------
    | API Routes
    |--------------------------------------------------------------------------
    |
    | Here is where you can register API routes for your application. These
    | routes are loaded by the RouteServiceProvider within a group which
    | is assigned the "api" middleware group. Enjoy building your API!
    |
    */
      
      
    Route::controller(RegisterController::class)->group(function(){
        Route::post('register', 'register');
        Route::post('login', 'login');
    });
            
    Route::middleware('auth:sanctum')->group( function () {
        Route::resource('products', ProductController::class);
    });

Step 6: Create Controller Files

app/Http/Controllers/API/BaseController.php 

<?php


    namespace App\Http\Controllers\API;
    
    
    use Illuminate\Http\Request;
    use App\Http\Controllers\Controller as Controller;
    
    
    class BaseController extends Controller
    {
        /**
         * success response method.
         *
         * @return \Illuminate\Http\Response
         */
        public function sendResponse($result, $message)
        {
            $response = [
                'success' => true,
                'data'    => $result,
                'message' => $message,
            ];
    
    
            return response()->json($response, 200);
        }
    
    
        /**
         * return error response.
         *
         * @return \Illuminate\Http\Response
         */
        public function sendError($error, $errorMessages = [], $code = 404)
        {
            $response = [
                'success' => false,
                'message' => $error,
            ];
    
    
            if(!empty($errorMessages)){
                $response['data'] = $errorMessages;
            }
    
    
            return response()->json($response, $code);
        }
    }

app/Http/Controllers/API/RegisterController.php

<?php
   
    namespace App\Http\Controllers\API;
       
    use Illuminate\Http\Request;
    use App\Http\Controllers\API\BaseController as BaseController;
    use App\Models\User;
    use Illuminate\Support\Facades\Auth;
    use Validator;
    use Illuminate\Http\JsonResponse;
       
    class RegisterController extends BaseController
    {
        /**
         * Register api
         *
         * @return \Illuminate\Http\Response
         */
        public function register(Request $request): JsonResponse
        {
            $validator = Validator::make($request->all(), [
                'name' => 'required',
                'email' => 'required|email',
                'password' => 'required',
                'c_password' => 'required|same:password',
            ]);
       
            if($validator->fails()){
                return $this->sendError('Validation Error.', $validator->errors());       
            }
       
            $input = $request->all();
            $input['password'] = bcrypt($input['password']);
            $user = User::create($input);
            $success['token'] =  $user->createToken('MyApp')->plainTextToken;
            $success['name'] =  $user->name;
       
            return $this->sendResponse($success, 'User register successfully.');
        }
       
        /**
         * Login api
         *
         * @return \Illuminate\Http\Response
         */
        public function login(Request $request): JsonResponse
        {
            if(Auth::attempt(['email' => $request->email, 'password' => $request->password])){ 
                $user = Auth::user(); 
                $success['token'] =  $user->createToken('MyApp')->plainTextToken; 
                $success['name'] =  $user->name;
       
                return $this->sendResponse($success, 'User login successfully.');
            } 
            else{ 
                return $this->sendError('Unauthorised.', ['error'=>'Unauthorised']);
            } 
        }
    }

app/Http/Controllers/API/ProductController.php

<?php
   
    namespace App\Http\Controllers\API;
       
    use Illuminate\Http\Request;
    use App\Http\Controllers\API\BaseController as BaseController;
    use App\Models\Product;
    use Validator;
    use App\Http\Resources\ProductResource;
    use Illuminate\Http\JsonResponse;
       
    class ProductController extends BaseController
    {
        /**
         * Display a listing of the resource.
         *
         * @return \Illuminate\Http\Response
         */
        public function index(): JsonResponse
        {
            $products = Product::all();
        
            return $this->sendResponse(ProductResource::collection($products), 'Products retrieved successfully.');
        }
        /**
         * Store a newly created resource in storage.
         *
         * @param  \Illuminate\Http\Request  $request
         * @return \Illuminate\Http\Response
         */
        public function store(Request $request): JsonResponse
        {
            $input = $request->all();
       
            $validator = Validator::make($input, [
                'name' => 'required',
                'detail' => 'required'
            ]);
       
            if($validator->fails()){
                return $this->sendError('Validation Error.', $validator->errors());       
            }
       
            $product = Product::create($input);
       
            return $this->sendResponse(new ProductResource($product), 'Product created successfully.');
        } 
       
        /**
         * Display the specified resource.
         *
         * @param  int  $id
         * @return \Illuminate\Http\Response
         */
        public function show($id): JsonResponse
        {
            $product = Product::find($id);
      
            if (is_null($product)) {
                return $this->sendError('Product not found.');
            }
       
            return $this->sendResponse(new ProductResource($product), 'Product retrieved successfully.');
        }
        
        /**
         * Update the specified resource in storage.
         *
         * @param  \Illuminate\Http\Request  $request
         * @param  int  $id
         * @return \Illuminate\Http\Response
         */
        public function update(Request $request, Product $product): JsonResponse
        {
            $input = $request->all();
       
            $validator = Validator::make($input, [
                'name' => 'required',
                'detail' => 'required'
            ]);
       
            if($validator->fails()){
                return $this->sendError('Validation Error.', $validator->errors());       
            }
       
            $product->name = $input['name'];
            $product->detail = $input['detail'];
            $product->save();
       
            return $this->sendResponse(new ProductResource($product), 'Product updated successfully.');
        }
       
        /**
         * Remove the specified resource from storage.
         *
         * @param  int  $id
         * @return \Illuminate\Http\Response
         */
        public function destroy(Product $product): JsonResponse
        {
            $product->delete();
       
            return $this->sendResponse([], 'Product deleted successfully.');
        }
    }

Step 7: Create Eloquent API Resources

php artisan make:resource ProductResource

app/Http/Resources/ProductResource.php

<?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
  
       */
      public function toArray(Request $request): array
      {
          return [
              'id' => $this->id,
              'name' => $this->name,
              'detail' => $this->detail,
              'created_at' => $this->created_at->format('d/m/Y'),
              'updated_at' => $this->updated_at->format('d/m/Y'),
          ];
      }
  }

Run Laravel App:

php artisan serve

 

Now, Go to your postman and check following apis.

make sure in details api we will use following headers as listed bellow:

'headers' => [

'Accept' => 'application/json',
    
'Authorization' => 'Bearer '.$accessToken,
    
    ]

For Run Apis Follow the Step and add URL ;

1) Register API: Verb:GET, URL:http://localhost:8000/api/register

2) Login API: Verb:GET, URL:http://localhost:8000/api/login

3) Product List API: Verb:GET, URL:http://localhost:8000/api/products

4) Product Create API: Verb:POST, URL:http://localhost:8000/api/products

5) Product Show API: Verb:GET, URL:http://localhost:8000/api/products/{id}

6) Product Update API: Verb:PUT, URL:http://localhost:8000/api/products/{id}

7) Product Delete API: Verb:DELETE, URL:http://localhost:8000/api/products/{id}