Faster PHP Cloud Hosting

How To Secure Laravel API Authentication with Sanctum - Security Guide

logo icon

Admin Nganggur

-

2025 August 13

iamge article

Have you ever wondered whether the API we have created has sufficient security to protect it from cyber attacks? In fact, many novice developers overlook an important aspect after successfully creating an API, namely how to protect APIs that store sensitive data from leaks. The way to address this issue is to implement token-based authentication for APIs in the applications we create, one of which is using Laravel Sanctum.

Laravel Sanctum provides a lightweight authentication system for SPAs (Single Page Applications), mobile applications, and simple APIs. This article will discuss the definition and features of Laravel Sanctum, as well as a guide to implementing secure API authentication in Laravel.

What is Laravel Sanctum

Laravel Sanctum is an official package or library that offers token-based authentication for Laravel applications. Sanctum is designed for Single Page Applications, Mobile Apps, and Simple APIs without using more complex systems such as Laravel Passport (OAuth2). Sanctum operates using two approaches:

  • API Tokens - for applications requiring classic token-based authentication.
  • Cookie-based SPA Authentication - for SPAs running on the same domain, using secure session cookies. However, in this discussion, we will use API Authentication Tokens.

Main Features of Laravel Sanctum

Laravel Sanctum has several outstanding features, namely:

  • API Authentication Tokens
  • SPA Authentication
  • Mobile App Authentication Support
  • Token Abilities / Scope Tokens
  • Token Expiration
  • Easy to Use and Lightweight

Preparation

Before implementing Laravel Sanctum in your Laravel application, make sure you have:

  • Laravel 12.x already installed.
  • PHP 8.2 or higher.
  • Composer.
  • A basic understanding of Laravel.
  • A database (MySQL, PostgreSQL, etc.).

Install Laravel Sanctum

Open the terminal and copy the script below.

composer require laravel/sanctum

Publish the Sanctum configuration.

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

Run the migration

php artisan migrate

Laravel Sanctum Configuration

  • Config Middleware

Open the bootstrap/app.php file and add the code below.

$middleware->statefulApi(); 

and

api: __DIR__./../routes/api.php’,

so that the full code for the app.php file becomes like this.

return Application::configure(basePath: dirname(__DIR__))
    ->withProviders()
    ->withRouting(
        web: __DIR__./../routes/web.php’,
        api: __DIR__./../routes/api.php’,
        commands: __DIR__./../routes/console.php’,
        health: /up’,
    )
    ->withMiddleware(function (Middleware $middleware) {
        $middleware->statefulApi(); 
    })
    ->withExceptions(function (Exceptions $exceptions) {
       
    })->create();
  • CORS

Paste the following command into the terminal to publish the cors.php configuration.

php artisan config:publish cors

Update the config/cors.php file to allow credentials.

‘supports_credentials’ => true,
  • Set Expired Token

Open the config/sanctum.php file to set the expired token in minutes.

‘expiration’ => 60 //1 hour

Implementation

  • User Model Configuration

Open the file app/Models/User.php and add the trait HasApiTokens as shown below.

<?php

namespace App\Models;

use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable
{
   use HasFactory, Notifiable, HasApiTokens;
}
  • Controller Configuration

Create a controller named AuthController to handle the authentication process.

php artisan make:controller Api/AuthController

Open the AuthController file and paste the code below.

<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\ValidationException;

class AuthController extends Controller
{
    public function register(Request $request)
    {
        $request->validate([
            'name' => 'required|string|max:255',
            'email' => 'required|string|email|max:255|unique:users',
            'password' => 'required|string|min:8|confirmed',
        ]);

        $user = User::create([
            'name' => $request->name,
            'email' => $request->email,
            'password' => Hash::make($request->password),
        ]);

        $token = $user->createToken('auth-token')->plainTextToken;

        return response()->json([
            'user' => $user,
            'message' => 'registration success'
        ], 201);
    }

    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.'],
            ]);
        }

        $token = $user->createToken('auth-token')->plainTextToken;

        return response()->json([
            'access_token' => $token,
            'token_type' => 'Bearer',
            'user' => $user,
            'message' => 'login success'
        ]);
    }

    public function logout(Request $request)
    {
        $request->user()->currentAccessToken()->delete();

        return response()->json([
            'message' => 'logout success'
        ]);
    }

    public function user(Request $request)
    {
        return response()->json([
            'user' => $request->user(),
            'message' => 'user data retrieved successfully'
        ]);
    }
}

Let's discuss some parts of the code above.

$token = $user->createToken(‘auth-token’)->plainTextToken;

The createToken() function is a method from the HasApiTokens trait to generate a token in the form of a plainTextToken.

$request->user()->currentAccessToken()->delete();

Deletes the token that has been generated and used by the user.

  • Update Route API

Create a file named api.php inside the routes/ folder, then paste the code below.

<?php

use App\Http\Controllers\Api\AuthController;
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::get('/get-user', [AuthController::class, 'user']);
});

We define middleware(‘auth:sanctum’) within a route group, which means that all routes within that group will be protected by auth:sanctum.

Testing the API Using Postman

We use the Postman tool to test the API we have created.

  1. Register User
  • POST /api/register
  • Body {“name”: “NganggurDev”, “email”: “bussines.nganggurdev@gmail.com”, “password”: “admin123”, ‘password_confirmation’: “admin123”} Postman Register Laravel Sanctum - NganggurDev
  1. Login
  • POST /api/login
  • Body {"email": "bussines.nganggurdev@gmail.com", "password": "admin123"} Postman Login Laravel Sanctum - NganggurDev
  1. Access Protected Route
  • GET /api/get-user
  • Header: Authorization: Bearer <access token>

User Has a Bearer Token (Authenticated) Postman Get User Laravel Sanctum - NganggurDev Unauthenticated Postman Get User Unauth Laravel Sanctum - NganggurDev 4. Logout

  • POST /api/logout
  • Header: Authorization: Bearer <access token> Postman Logout Laravel Sanctum - NganggurDev

Common Problems

  • CORS Problem

Solution: Make sure the CORS configuration is correct.

  • 401 Unauthorized

Solution: Check if the Authorization header is formatted correctly: Bearer {token}.

  • Session with SPA

Solution: Ensure to call api /sanctum/csrf-cookie before making an authenticated request in SPA.

  • Token Not Expiring as Expected

Solution: Configure the expiration time in config/sanctum.php and implement custom expiration for specific tokens if needed.

  • Duplicate Tokens for the Same User

Solution: Implement a strategy to revoke old tokens upon new login or limit the maximum number of active tokens per user.

Conclusion

Laravel Sanctum provides a solution for securing sensitive data in modern web applications. By following this guide, we have learned the basics of implementing secure API authentication in Laravel 12.

Thank you.

Tags :

laravel security

how to protect your api route with laravel sanctum

secure api auth with laravel sanctum

laravel

laravel sanctum

rest api

learn coding with nganggurdev

Like the articles on NganggurDev? Let's give support to the writer. Thank you very much!
Load WordPress Sites in as fast as 37ms!

Want to read more? Click me!