Understanding Laravel Authentication Options
By day 22 of your Laravel journey, you've likely encountered authentication—that critical task of verifying who users are and protecting what they can access. The Laravel ecosystem offers multiple authentication packages, each designed for different architectural patterns and client types. In this guide, we'll explore Laravel authentication options: best practices explained, cutting through the confusion about Breeze, Jetstream, Fortify, Sanctum, and Passport so you can choose the right tool for your project.
The Four Main Authentication Packages
Laravel doesn't force you into a single authentication mold. Instead, the framework provides purpose-built packages that solve different problems. Understanding when to reach for each one is the foundation of making good architectural decisions.
| Package | Type | Best For | Client Type |
|---|---|---|---|
| Breeze | Starter kit with UI | Simple apps with server-rendered views | Traditional web browsers |
| Jetstream | Starter kit with UI | Feature-rich apps (teams, 2FA) | Traditional web browsers |
| Fortify | Headless backend | Custom UI, decoupled frontends | Any frontend framework |
| Sanctum | Token-based API auth | SPAs and mobile apps | JavaScript frontend, native mobile |
| Passport | OAuth2 server | Third-party integrations | External applications |
Breeze and Jetstream: Starter Kits with Built-In UI
When you need to launch quickly with authentication already wired up, these starter kits scaffold the entire flow—login, registration, password reset, and email verification—complete with views and routes.
Breeze is the lightweight option. It gives you login, registration, password reset, and email verification with minimal overhead. Think of it as the foundation for a traditional web application where your Laravel backend renders HTML.
Jetstream is Breeze's feature-rich cousin. It adds team management, two-factor authentication, session management, and API token support out of the box. If your product requires multiple users per account or security-conscious enterprise features, Jetstream saves significant development time.
Both scaffold the authentication logic you'd otherwise write by hand, but they're opinionated. If you need a highly customized authentication flow or your frontend is completely decoupled from your backend, these starter kits may feel restrictive.
// Installing Breeze
composer require laravel/breeze --dev
php artisan breeze:install
// Choosing a stack (Blade, React, Vue, API-only)
php artisan breeze:install blade
php artisan breeze:install react
php artisan breeze:install api // Scaffolds routes but no views
Fortify: Headless Authentication Backend
Fortify is the authentication engine without the views. It provides all the controllers, routes, and logic for login, registration, password reset, two-factor authentication, and email verification—but you build the UI yourself.
This is your choice when your frontend is a separate Vue.js app, a React application, or a custom UI library that doesn't fit Breeze's scaffolding. Fortify handles the backend orchestration while your frontend team builds the login form and handles the responses.
A typical flow: your frontend sends credentials to a Fortify endpoint, Fortify validates and authenticates the user, returns a session cookie, and your frontend redirects to the dashboard. Fortify does the heavy lifting; you control the presentation.
// Fortify configuration (config/fortify.php)
'features' => [
Features::registration(),
Features::resetPasswords(),
Features::emailVerification(),
Features::twoFactorAuthentication([
'confirmPassword' => true,
]),
],
// Fortify redirects after login (customize in FortifyServiceProvider)
Fortify::authenticateUsing(function (Request $request) {
$user = User::where('email', $request->email)->first();
if ($user && Hash::check($request->password, $user->password)) {
return $user;
}
});
Sanctum: The Right Choice for Most Modern Apps
Sanctum is Laravel's multi-purpose authentication library, and for most teams, it's the answer. It handles cookie-based authentication for single-page applications and token-based authentication for mobile clients—solving the two dominant client architectures in modern development.
Why Sanctum wins: It's simpler than Passport, handles both SPAs and APIs elegantly, and requires minimal configuration. When your frontend is a Next.js app on the same domain, Sanctum manages session cookies automatically. When your mobile app needs API access, Sanctum issues tokens. One library, two problems solved.
For SPAs, Sanctum uses a CSRF token approach. Your frontend loads the app, receives a session cookie via a `/sanctum/csrf-token` endpoint, and uses that token for subsequent requests. This is stateful—the server maintains session state—and mirrors traditional web application security.
For mobile and external API clients, Sanctum issues bearer tokens. A mobile app authenticates once, receives a token, and includes it in the `Authorization` header for all future requests.
// In routes/api.php with Sanctum middleware
Route::middleware('auth:sanctum')->group(function () {
Route::get('/user', function (Request $request) {
return $request->user();
});
Route::post('/posts', [PostController::class, 'store']);
Route::delete('/posts/{post}', [PostController::class, 'destroy']);
});
// Mobile app authentication flow
// POST /api/login with email and password
// Response: { "token": "1|xyz..." }
// Future requests: Authorization: Bearer 1|xyz...
Sanctum also supports ability checks and token scopes—fine-grained permissions on API tokens—which is essential for security. A mobile app might issue tokens with only `read` scope, while an admin panel token has full access.
// Issuing a token with scopes
$token = $user->createToken('api-token', ['posts:read', 'posts:write']);
// Checking scopes in middleware or controllers
if ($request->user()->tokenCan('posts:write')) {
// Allow write operation
}
Passport: OAuth2 When External Apps Need Access
Passport turns your Laravel application into an OAuth2 provider. Think of scenarios where third parties need authenticated access to your API: a partner integration platform, a mobile app published in an app store, or a desktop client managed by another team.
When do you need OAuth2? When you need to grant access to external applications without sharing user passwords, when you want granular permission management, or when you're building an API that multiple independent clients will consume.
Passport is more complex than Sanctum. It requires setting up clients, scopes, and managing token lifecycle. For most internal projects or single-tenant SaaS applications, Sanctum is sufficient. Reach for Passport when you're building an API platform that strangers will integrate with.
// Creating an OAuth2 client via Passport
php artisan passport:client
// In your frontend or mobile app
POST /oauth/token
{
"grant_type": "password",
"client_id": "CLIENT_ID",
"client_secret": "CLIENT_SECRET",
"username": "user@example.com",
"password": "password",
"scope": "*"
}
// Response includes access_token and refresh_token
Password Hashing: Bcrypt and Argon2
Regardless of which authentication package you choose, never store passwords in plain text. Laravel uses bcrypt by default, with argon2i and argon2id as alternatives.
Bcrypt is battle-tested and widely supported. Argon2 is newer and theoretically superior against GPU-based attacks, but for most applications, bcrypt is perfectly adequate. Laravel's Hash facade abstracts away the complexity.
// In config/hashing.php
'driver' => env('HASH_DRIVER', 'bcrypt'),
'bcrypt' => [
'rounds' => env('BCRYPT_ROUNDS', 10),
],
'argon2' => [
'memory' => 65536,
'threads' => 2,
'time' => 4,
],
// Hashing a password
$hashedPassword = Hash::make($request->password);
// Verifying a password
if (Hash::check($request->password, $user->password)) {
// Password is correct
}
// Checking if a password needs rehashing (after algorithm change)
if (Hash::needsRehash($user->password)) {
$user->password = Hash::make($user->password);
$user->save();
}
The rounds parameter controls how computationally expensive hashing is. Higher rounds mean slower hashing—good for security but at the cost of login latency. Ten rounds is the default and balances security with user experience. Increase it only if you're willing to accept slower logins.
Common Mistakes
Using Passport when Sanctum suffices: Passport is powerful but comes with complexity. Most teams reach for it unnecessarily. Start with Sanctum and migrate only if you genuinely need OAuth2 semantics.
Storing passwords without hashing: We've all seen it. Don't. Always use Hash::make() when storing passwords and Hash::check() when verifying. Laravel makes this trivial; there's no excuse.
Forgetting to protect API routes: Applying authentication middleware to public endpoints doesn't prevent attacks; applying it to private endpoints does. Audit your routes regularly to ensure sensitive operations require authentication.
Issuing tokens without expiration or scopes: API tokens should have a lifespan and limited permissions. Sanctum and Passport support both; use them. A token valid forever with full access is a security liability.
Mixing authentication patterns inconsistently: Choose one pattern per client type and stick with it. Don't issue cookies to mobile apps or expect a browser-based SPA to use bearer tokens. Consistency reduces bugs and makes security reviews easier.
Key Takeaways
- Use Breeze for simple server-rendered web apps where you want authentication scaffolded quickly.
- Choose Jetstream if you need advanced features like teams or two-factor authentication built-in.
- Reach for Fortify when your frontend is a separate codebase and you want the authentication backend decoupled from the UI.
- Sanctum is the default choice for most modern applications—it handles both SPAs and mobile APIs cleanly.
- Reserve Passport for OAuth2 scenarios where external applications need authenticated access to your API platform.
- Always hash passwords with
bcryptorargon2. Laravel does this by default; trust the framework. - Protect API routes consistently. Audit your authentication middleware regularly and ensure sensitive operations are gated.
- Issue API tokens with expiration dates and scoped permissions. Token security is as critical as user password security.






Comments
Loading comments…