LaravelPHPAuthenticationAPI

Laravel Sanctum vs Passport vs JWT: Which to Choose for API Auth?

··10 min read

When building a Laravel API, one of the first architectural decisions is authentication. You have three main options: Laravel Sanctum, Laravel Passport, and JWT via the tymon/jwt-auth package. Each solves a different problem. Picking the wrong one creates unnecessary complexity.

Quick Decision Guide

  • SPA or mobile app consumed by your own frontend → use Sanctum
  • Third-party OAuth2 (other apps authenticate against your API) → use Passport
  • Microservices, stateless tokens, cross-domain auth → use JWT

Laravel Sanctum

Sanctum is Laravel's lightweight token authentication package. It supports two mechanisms: opaque API tokens stored in your database, and cookie-based session authentication for SPAs on the same domain.

bash
composer require laravel/sanctum
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
php artisan migrate
php
// Issue a token
public function login(Request $request)
{
    $request->validate(['email' => 'required|email', 'password' => 'required']);

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

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

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

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

Token abilities (scopes) let you restrict what each token can do — great for generating read-only tokens for third-party integrations without exposing write access.

When to use Sanctum

  • Your API is consumed by your own React/Vue/mobile app
  • You want simple token management with database revocation
  • You don't need OAuth2 flows (authorization codes, client credentials)
  • You want token abilities (lightweight scoping)

Laravel Passport

Passport implements a full OAuth2 server in Laravel. It supports authorization codes, personal access tokens, password grants, and client credentials. It's significantly heavier than Sanctum.

bash
composer require laravel/passport
php artisan migrate
php artisan passport:install

Passport is the right choice when external applications need to authenticate against your API using OAuth2 flows — like when you're building an API platform that third-party developers will integrate with.

When to use Passport

  • You're building a public API platform for third-party developers
  • You need OAuth2 authorization code flow
  • You need client credentials grant for machine-to-machine auth
  • Compliance requires a standards-based OAuth2 implementation

JWT (tymon/jwt-auth)

JWT tokens are self-contained — the payload includes user claims signed with a secret. The server doesn't need to query the database on every request to validate the token. This makes JWT ideal for stateless, distributed, or microservice architectures.

bash
composer require tymon/jwt-auth
php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"
php artisan jwt:secret
php
// config/auth.php
'guards' => [
    'api' => [
        'driver'   => 'jwt',
        'provider' => 'users',
    ],
],

// AuthController
public function login(Request $request)
{
    $credentials = $request->only('email', 'password');

    if (!$token = auth('api')->attempt($credentials)) {
        return response()->json(['error' => 'Unauthorized'], 401);
    }

    return response()->json([
        'access_token' => $token,
        'token_type'   => 'bearer',
        'expires_in'   => auth('api')->factory()->getTTL() * 60,
    ]);
}

public function refresh()
{
    return response()->json([
        'access_token' => auth('api')->refresh(),
        'token_type'   => 'bearer',
        'expires_in'   => auth('api')->factory()->getTTL() * 60,
    ]);
}

When to use JWT

  • Microservices where multiple services validate tokens without a shared database
  • Cross-domain authentication (your API and frontend are on different domains)
  • Mobile apps where you need token refresh flows
  • High-traffic APIs where eliminating the database lookup per request matters

Comparison Table

  • Complexity: Sanctum (low) < JWT (medium) < Passport (high)
  • Database lookup per request: Sanctum (yes) | JWT (no) | Passport (yes)
  • Token revocation: Sanctum (instant) | JWT (requires blacklist) | Passport (instant)
  • OAuth2 support: Sanctum (no) | JWT (no) | Passport (full)
  • Best for: Sanctum → SPAs | JWT → microservices | Passport → public API platforms

Note: For 90% of Laravel projects — a standard SPA or mobile backend — Sanctum is the right choice. The added complexity of Passport or JWT is rarely justified unless you have a specific need for OAuth2 flows or stateless tokens.

Token Revocation with JWT

The biggest downside of JWT is that tokens can't be truly revoked without maintaining a blacklist — which reintroduces the database lookup you were trying to avoid. Use short expiry times (15–60 minutes) with refresh tokens to mitigate this.

php
// In .env
JWT_TTL=60          # Access token expires in 60 minutes
JWT_REFRESH_TTL=20160  # Refresh window: 2 weeks

// Logout: add token to blacklist
public function logout()
{
    auth('api')->logout(); // Invalidates the current token
    return response()->json(['message' => 'Successfully logged out']);
}
Pratik Yewale

Pratik Yewale

Assistant Manager – Software at Qing Aamby City Developers Corporations Limited. Previously Backend Developer at Neuromonk Infotech building scalable APIs, ERP systems, and booking platforms. Published researcher in cricket analytics.

View Portfolio