Laravel Sanctum vs Passport vs JWT: Which to Choose for API Auth?
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.
composer require laravel/sanctum
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
php artisan migrate// 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.
composer require laravel/passport
php artisan migrate
php artisan passport:installPassport 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.
composer require tymon/jwt-auth
php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"
php artisan jwt:secret// 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.
// 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
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