How To Secure Laravel API Authentication with Sanctum - Security Guide

logo icon

Admin Teguh

-

17 September 2025

How To Secure Laravel API Authentication with Sanctum - Security Guide

Ever wondered if your API has enough security to keep hackers at bay? Here's the reality, many beginner developers celebrate when their API works but completely forget about protecting sensitive data from prying eyes. The solution? Implementing token-based authentication for your APIs and Laravel Sanctum is the perfect tool for the job.

Laravel Sanctum gives you a lightweight authentication system that's perfect for SPAs (Single Page Applications), mobile apps, and simple APIs. In this guide, we'll explore what Laravel Sanctum brings to the table and walk through implementing secure API authentication in Laravel.

What is Laravel Sanctum

Laravel Sanctum is Laravel's official package that handles token-based authentication for Laravel applications. Unlike the more complex Laravel Passport (which uses OAuth2), Sanctum is designed specifically for Single Page Applications, Mobile Apps, and Simple API. Sanctum works with two different approaches:

  • API Tokens - for applications that need classic token-based authentication

  • Cookie-based SPA Authentication - for SPAs running on the same domain, using secure session cookies

For this tutorial, we'll focus on API Token Authentication.

Key Features of Laravel Sanctum

Laravel Sanctum comes packed with useful features that make authentication a breeze :

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

Getting Ready

Before we dive into implementing Laravel Sanctum, make sure you've got:

  • Laravel 12.x installed and running
  • PHP 8.2 or higher
  • Composer
  • Basic understanding of Laravel concepts
  • A database (MySQL, PostgreSQL, etc.)

Installing Laravel Sanctum

Open your terminal and run this command to install Sanctum :

composer require laravel/sanctum

Next, publish the Sanctum configuration:

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

Run the migration to create the necessary database tables:

php artisan migrate

Configuring Laravel Sanctum

  • Setting Up Middleware

Open bootstrap/app.php and add this code:

$middleware->statefulApi(); 

and

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

Here's what your complete app.php file should look like:

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 Configuration

Run this command to publish the CORS configuration file:

php artisan config:publish cors

Update config/cors.php to allow credentials:

'supports_credentials' => true,
  • Token Expiration Settings

Open config/sanctum.php to set token expiration time (in minutes):

'expiration' => 60 //1 hour

Implementation

  • Configuring the User Model

Open app/Models/User.php and add the HasApiTokens trait :

<?php
namespace App\Models;
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable
{
   use HasFactory, Notifiable, HasApiTokens;
}
  • Creating the Controller

Generate an AuthController to handle authentication processes :

php artisan make:controller Api/AuthController

Open the AuthController file and add this code:

<?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 break down some key parts of this code:

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

The createToken() method comes from the HasApiTokens trait and generates a plainTextToken for authentication.

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

This line deletes the token that was generated and used by the user, effectively logging them out.

  • Setting Up API Routes

Create or update the api.php file in the routes/ folder with this code:

<?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're using middleware('auth:sanctum') in a route group, which means all routes inside this group will be protected by auth:sanctum authentication.

Testing Your API with Postman

Let's use Postman to test our newly created API endpoints.

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

Authenticated User Response

When you include a valid Bearer token, you'll get the user data successfully. Postman Get User Laravel Sanctum - NganggurDev Unauthenticated Response

Without a valid token, you'll receive a 401 Unauthorized error. Postman Get User Unauth Laravel Sanctum - NganggurDev 4. User Logout

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

Common Issues You Might Encounter

  • CORS Problems Solution: Double-check that your CORS configuration is set up correctly.

  • 401 Unauthorized Error Solution: Make sure your Authorization header is formatted correctly: Bearer {token}.

  • SPA Session Issues Solution: For SPAs, make sure to call the /sanctum/csrf-cookie endpoint before making authenticated requests.

  • Token Expiration Not Working as Expected Solution: Configure the expiration time in config/sanctum.php and implement custom expiration logic for specific tokens if needed.

  • Duplicate Tokens for Same User Solution: Implement a strategy to revoke old tokens when users log in again, or limit the maximum number of active tokens per user.

Wrapping Up

Laravel Sanctum provides an elegant solution for securing sensitive data in modern web applications. By following this guide, you've learned the fundamentals of implementing secure API authentication in Laravel 12.

Your APIs are now protected with token-based authentication that's both secure and easy to manage. This foundation will serve you well as you build more complex applications that require robust security measures.

Thanks for following along!

Teguh Budi Laksono

Teguh Budi Laksono

"not a perfect person, just someone who keeps learning and trying, because he believes that big dreams are born from a long and consistent process."

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!

Want to read more? Click me!