SyntaxStudy
Sign Up
Laravel Laravel Sanctum for API Token Authentication
Laravel Beginner 1 min read

Laravel Sanctum for API Token Authentication

Laravel Sanctum provides a featherweight authentication system for SPAs, mobile applications, and simple token-based APIs. Unlike Passport, Sanctum does not implement OAuth2. Instead, it issues plain API tokens stored in the personal_access_tokens table, and for SPAs it leverages Laravel's cookie-based session authentication with CSRF protection. To use Sanctum token authentication, the User model uses the HasApiTokens trait. Tokens are created with $user->createToken('token-name')->plainTextToken. The plain text token is shown once at creation time; only its hashed version is stored. Token abilities (scopes) restrict what a token can do: $user->createToken('name', ['posts:read', 'posts:write']). Sanctum routes are protected with the auth:sanctum middleware. Inside a protected route, the authenticated user is retrieved via $request->user(). Token abilities are checked with $request->user()->tokenCan('posts:write'). Tokens can be revoked individually ($token->delete()) or all at once ($user->tokens()->delete()), enabling a token management dashboard for API clients.
Example
<?php
// Install Sanctum
// composer require laravel/sanctum
// php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
// php artisan migrate

// app/Models/User.php — add the trait
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;
}

// app/Http/Controllers/Api/AuthController.php
namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

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

        if (!Auth::attempt($credentials)) {
            return response()->json(['message' => 'Invalid credentials'], 401);
        }

        $token = $request->user()->createToken('api-token', ['posts:read', 'posts:write']);

        return response()->json(['token' => $token->plainTextToken]);
    }

    public function logout(Request $request)
    {
        $request->user()->currentAccessToken()->delete();
        return response()->json(['message' => 'Logged out']);
    }
}