Skip to main content
Back to Blog

Laravel 12 Sanctum API Authentication Tutorial (2026 Full Guide)

Laravel 12 Sanctum API Authentication Tutorial (2026 Full Guide) – cover image

In this 2026 guide, you’ll learn how to build a clean, secure API authentication system in Laravel 12 using Laravel Sanctum. We’ll cover installation, login & logout, protected routes, Postman testing, and best practices for modern APIs that power SPAs and mobile apps.


1. What Is Laravel Sanctum?

Laravel Sanctum is a lightweight authentication system for APIs, SPAs, mobile apps, and simple token-based login. It’s perfect in 2026 because it gives you secure token auth without the complexity of OAuth or Laravel Passport.

Sanctum is great when you want:

  • Simple personal access tokens for your users
  • Secure APIs for React / Vue / mobile apps
  • Ability to create, revoke, and limit tokens
  • First-class support inside modern Laravel

In simple terms: “Sanctum makes API authentication easy while still being secure and production-ready.”


2. Install Sanctum in Laravel 12 (2026)

First, install Sanctum via Composer:

composer require laravel/sanctum

Then publish the configuration and migrations:

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

After this, your database will have a personal_access_tokens table where Sanctum stores tokens for users.


3. Laravel 12 Middleware Setup (Important Update)

In Laravel 12 (and Laravel 11), the framework no longer uses app/Http/Kernel.php. Middleware configuration has moved to bootstrap/app.php.

This is a major architectural improvement—but here’s the good news:

If you are using Laravel Sanctum with token-based authentication (Authorisation: Bearer tokens), you do NOT need to add or modify any middleware manually.

Laravel Sanctum works out of the box for API authentication in Laravel 12. You simply protect your API routes using the auth:sanctum middleware.

✅ Laravel 12 Note

For token-based APIs (mobile apps, SPAs, Postman testing), Sanctum does not require any middleware configuration in bootstrap/app.php. Just use auth:sanctum on your routes.

This keeps your API authentication setup clean, minimal, and fully aligned with modern Laravel standards.


4. Enable Token Support in the User Model

Sanctum uses a trait called HasApiTokens on your User model to manage tokens.

Open app/Models/User.php and update it like this:

<?php

namespace App\Models;

use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable
{
    use HasApiTokens, Notifiable;

    // ...
}

Now each user can have multiple personal access tokens (for example: web app, mobile app, admin panel, etc.).


5. Create Login API to Issue Tokens

Let’s build a dedicated API controller for authentication.

Generate a controller:

php artisan make:controller Api/AuthController

Now open app/Http/Controllers/Api/AuthController.php and add a login method:

<?php

namespace App\Http\Controllers\Api;

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

class AuthController extends Controller
{
    public function login(Request $request)
    {
        // 1. Validate request
        $request->validate([
            'email'    => ['required', 'email'],
            'password' => ['required'],
        ]);

        // 2. Find user by email
        $user = User::where('email', $request->input('email'))->first();

        // 3. Check if user exists and password matches
        if (! $user || ! Hash::check($request->input('password'), $user->password)) {
            return response()->json([
                'message' => 'Invalid credentials',
            ], 401);
        }

        // 4. Create new personal access token
        $token = $user->createToken('api_token')->plainTextToken;

        // 5. Return token in JSON response
        return response()->json([
            'message' => 'Login successful',
            'token'   => $token,
            'user'    => $user,
        ]);
    }
}

What this does:

  • Validates email/password input
  • Checks the credentials against the database
  • Creates a new Sanctum token using createToken()
  • Returns the token (and user) as JSON

Your frontend or mobile app will store this token (for example, in localStorage or secure mobile storage) and send it on all future API calls.


6. Logout API — Revoke the Current Token

For logout, we want to delete the current token so that it can’t be used anymore.

Add this inside the same AuthController:

public function logout(Request $request)
{
    // Delete the token that was used to authenticate the current request
    $request->user()?->currentAccessToken()?->delete();

    return response()->json([
        'message' => 'Logged out successfully',
    ]);
}

This doesn’t delete all tokens for the user—only the one used in the current API call. That’s ideal when a user has multiple logged-in devices.


7. Protecting API Routes with Sanctum

Open your routes/api.php file and wire up the auth routes:

<?php

use App\Http\Controllers\Api\AuthController;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;

Route::post('/login', [AuthController::class, 'login']);

// Routes that require authentication
Route::middleware('auth:sanctum')->group(function () {
    Route::post('/logout', [AuthController::class, 'logout']);

    Route::get('/user', function (Request $request) {
        return $request->user();
    });

    // Example protected endpoint
    Route::get('/dashboard-stats', function () {
        return [
            'visits' => 1234,
            'sales'  => 57,
        ];
    });
});

Any route inside the Route::middleware('auth:sanctum') group requires a valid token. The client must send the token like this:

GET /api/user HTTP/1.1
Host: your-app.test
Authorization: Bearer 1|exampleapitokenstring...
Accept: application/json

8. Testing Sanctum with Postman in 2026

Let’s test your API step by step using Postman (or any API client).

8.1 Login and Get Token

  1. Open Postman and create a new POST request to /api/login.
  2. Set the request body type to JSON.
  3. Use a payload like this:
{
  "email": "test@example.com",
  "password": "password"
}

If the user exists and the password is correct, you’ll get a response like:

{
  "message": "Login successful",
  "token": "1|abc123verylongapitoken...",
  "user": {
    "id": 1,
    "name": "Test User",
    "email": "test@example.com",
    "created_at": "2026-01-01T10:00:00.000000Z",
    "updated_at": "2026-01-01T10:00:00.000000Z"
  }
}

8.2 Call a Protected Route

  1. Copy the token value from the login response.
  2. Create a new GET request to /api/user (or any protected route).
  3. In the Headers tab, add:
Authorization: Bearer 1|abc123verylongapitoken...
Accept: application/json

If everything is set up correctly, the API will return the authenticated user’s details instead of Unauthenticated.

8.3 Logout

  1. Create a POST request to /api/logout.
  2. Use the same Authorization: Bearer <token> header.

Response example:

{
  "message": "Logged out successfully"
}

After this, using the same token again should result in a 401 Unauthenticated response.


9. Common Sanctum Issues and Fixes

9.1 “Unauthenticated.”

Cause: The Authorization header is missing or incorrect.

Fix: Always send the header like this:

Authorization: Bearer <your_token_here>

Also check that your API routes are using auth:sanctum and that the token has not been deleted.

9.2 CORS / SPA Problems

If you’re calling the API from a different domain (like a React frontend), you might see CORS errors.

In config/cors.php, you can expose the Authorization header:

'exposed_headers' => ['Authorization'],

Also ensure your allowed_origins or allowed_origins_patterns are correctly configured for your frontend domain.

9.3 Token Works in Postman but Not in Frontend

Possible causes:

  • Frontend is not sending the Authorization header correctly
  • Token is being stripped or modified by a proxy
  • You’re mixing cookies + tokens incorrectly

In 2026, a common pattern is: use Bearer tokens in the Authorization header for SPAs and mobile apps, and use cookies with CSRF for classic server-rendered apps.


10. Best Practices for Sanctum in 2026

10.1 Use Short-Lived Tokens Where Possible

Sanctum tokens don’t expire by default. You can implement your own expiry logic or rotate tokens periodically (for example, regenerate a token every few weeks and revoke the old ones).

10.2 Use Token Abilities

Abilities are like simple “scopes” for tokens. For example, you can issue a token that can only read data but not write.

$token = $user->createToken('mobile_app', ['read', 'write'])->plainTextToken;

Then in your code, you can check:

if ($request->user()->tokenCan('write')) {
    // allow write actions
}

10.3 Always Use HTTPS in Production

Never send API tokens over plain HTTP. Use HTTPS in production so that your tokens are encrypted in transit.

10.4 Revoke Tokens on Logout and When Compromised

Whenever a user logs out, loses a device, or reports suspicious activity, revoke their tokens. You can delete one token or all tokens for that user:

// Delete ALL tokens for a user
$user->tokens()->delete();

11. Conclusion

In this 2026 guide, you learned how to set up Laravel 12 Sanctum API authentication step by step:

  • Installing Sanctum and running migrations
  • Adding the Sanctum middleware and HasApiTokens trait
  • Building login and logout API endpoints
  • Protecting routes with auth:sanctum
  • Testing everything with Postman
  • Handling common errors and following best practices

Sanctum gives you a clean, modern way to secure APIs for SPAs, mobile apps, and microservices without the overhead of full OAuth.

From here, you can:

  • Integrate this API with a Vue / React or Livewire frontend
  • Build separate tokens for mobile apps and admin dashboards
  • Add role-based permissions on top of Sanctum

If you enjoyed this tutorial, you might also like: