Introduction to Authentication in Laravel
Authentication is the process of verifying the identity of a user, while authorization determines what actions a user can perform. Laravel provides a complete authentication system out of the box, making it easy to implement secure user login, registration, and access control.
Laravel Authentication Starters
Laravel offers several starter kits for authentication:
- Laravel Breeze: Minimal authentication scaffolding with Blade templates
- Laravel Jetstream: Full-featured authentication with teams support
- Laravel Fortify: Headless authentication backend (API-friendly)
- Laravel Sanctum: API token authentication for SPAs
Note: Laravel Breeze is the simplest option and perfect for learning. It includes login, registration, password reset, email verification, and password confirmation.
Installing Laravel Breeze
To install Laravel Breeze in a fresh Laravel application:
# Install Breeze via Composer
composer require laravel/breeze --dev
# Install Breeze scaffolding
php artisan breeze:install
# Options:
# - Blade (default)
# - React
# - Vue
# - API (for headless applications)
# Compile assets
npm install
npm run dev
# Run migrations
php artisan migrate
After installation, Breeze provides the following routes automatically:
// Authentication routes
/login - Login form
/register - Registration form
/forgot-password - Password reset request
/reset-password - Password reset form
/verify-email - Email verification
/confirm-password - Password confirmation
/logout - Logout (POST)
// Protected routes
/dashboard - User dashboard (auth required)
The User Model
Laravel comes with a User model that implements authentication contracts:
<?php
namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
use Notifiable;
protected $fillable = [
'name',
'email',
'password',
];
protected $hidden = [
'password',
'remember_token',
];
protected $casts = [
'email_verified_at' => 'datetime',
'password' => 'hashed', // Laravel 10+
];
}
Tip: The User model extends Authenticatable, which provides all authentication functionality. The Notifiable trait allows sending notifications to users.
Manual Authentication
You can manually authenticate users without using starter kits:
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class LoginController extends Controller
{
public function showLoginForm()
{
return view('auth.login');
}
public function login(Request $request)
{
// Validate credentials
$credentials = $request->validate([
'email' => ['required', 'email'],
'password' => ['required'],
]);
// Attempt to authenticate
if (Auth::attempt($credentials, $request->boolean('remember'))) {
// Regenerate session to prevent fixation
$request->session()->regenerate();
return redirect()->intended('dashboard');
}
// Authentication failed
return back()->withErrors([
'email' => 'The provided credentials do not match our records.',
])->onlyInput('email');
}
public function logout(Request $request)
{
Auth::logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
return redirect('/');
}
}
Protecting Routes with Authentication
Use the auth middleware to require authentication:
<?php
use App\Http\Controllers\DashboardController;
use Illuminate\Support\Facades\Route;
// Protect single route
Route::get('/dashboard', [DashboardController::class, 'index'])
->middleware('auth');
// Protect multiple routes with group
Route::middleware(['auth'])->group(function () {
Route::get('/dashboard', [DashboardController::class, 'index']);
Route::get('/profile', [ProfileController::class, 'show']);
Route::get('/settings', [SettingsController::class, 'index']);
});
// Protect routes in controller constructor
class DashboardController extends Controller
{
public function __construct()
{
$this->middleware('auth');
// Except specific methods
$this->middleware('auth')->except(['index', 'show']);
// Only specific methods
$this->middleware('auth')->only(['create', 'store', 'edit', 'update']);
}
}
Accessing the Authenticated User
Retrieve the currently authenticated user in multiple ways:
<?php
use Illuminate\Support\Facades\Auth;
use Illuminate\Http\Request;
// Using Auth facade
$user = Auth::user();
$id = Auth::id();
// Check if authenticated
if (Auth::check()) {
// User is logged in
}
// Using Request object
public function index(Request $request)
{
$user = $request->user();
}
// Using auth() helper
$user = auth()->user();
$id = auth()->id();
// In Blade views
@auth
<p>Welcome, {{ auth()->user()->name }}</p>
@endauth
@guest
<p>Please login</p>
@endguest
Email Verification
Laravel provides built-in email verification functionality:
<?php
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
// Implement MustVerifyEmail contract
class User extends Authenticatable implements MustVerifyEmail
{
// ...
}
// In routes/web.php - protect routes with verified middleware
Route::middleware(['auth', 'verified'])->group(function () {
Route::get('/dashboard', [DashboardController::class, 'index']);
});
Note: Email verification requires mail configuration in your .env file. For local development, use Mailtrap or log driver.
Password Reset
Laravel Breeze includes password reset out of the box. Here's how it works manually:
<?php
use Illuminate\Support\Facades\Password;
// Send password reset link
public function sendResetLink(Request $request)
{
$request->validate(['email' => 'required|email']);
$status = Password::sendResetLink(
$request->only('email')
);
return $status === Password::RESET_LINK_SENT
? back()->with(['status' => __($status)])
: back()->withErrors(['email' => __($status)]);
}
// Reset password
public function resetPassword(Request $request)
{
$request->validate([
'token' => 'required',
'email' => 'required|email',
'password' => 'required|min:8|confirmed',
]);
$status = Password::reset(
$request->only('email', 'password', 'password_confirmation', 'token'),
function ($user, $password) {
$user->password = $password;
$user->save();
}
);
return $status === Password::PASSWORD_RESET
? redirect()->route('login')->with('status', __($status))
: back()->withErrors(['email' => [__($status)]]);
}
Authentication Guards
Guards define how users are authenticated for each request. Laravel supports multiple guards for different user types:
// config/auth.php
return [
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'admin' => [
'driver' => 'session',
'provider' => 'admins',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
'admins' => [
'driver' => 'eloquent',
'model' => App\Models\Admin::class,
],
],
];
Using different guards:
<?php
// Use specific guard
if (Auth::guard('admin')->attempt($credentials)) {
// Admin authenticated
}
// Logout from specific guard
Auth::guard('admin')->logout();
// Protect routes with specific guard
Route::middleware(['auth:admin'])->group(function () {
Route::get('/admin/dashboard', [AdminController::class, 'index']);
});
// Get user from specific guard
$admin = Auth::guard('admin')->user();
Basic Authorization with Gates
Authorization determines what authenticated users can do. Gates are simple closures for authorization logic:
<?php
// app/Providers/AuthServiceProvider.php
namespace App\Providers;
use App\Models\Post;
use App\Models\User;
use Illuminate\Support\Facades\Gate;
class AuthServiceProvider extends ServiceProvider
{
public function boot(): void
{
// Define a gate
Gate::define('update-post', function (User $user, Post $post) {
return $user->id === $post->user_id;
});
// Gate with no model (check user property)
Gate::define('manage-users', function (User $user) {
return $user->is_admin;
});
}
}
// Using gates in controllers
public function update(Request $request, Post $post)
{
Gate::authorize('update-post', $post);
// Alternative: throws 403 if unauthorized
if (Gate::denies('update-post', $post)) {
abort(403);
}
// Or use allows()
if (Gate::allows('update-post', $post)) {
// Update the post
}
}
// In Blade views
@can('update-post', $post)
<a href="{{ route('posts.edit', $post) }}">Edit</a>
@endcan
Tip: Gates are best for simple authorization checks. For more complex authorization logic, use Policies (covered in next lesson).
Exercise 1: Create Authentication System
Install Laravel Breeze in a fresh Laravel project and customize the registration form to include a "phone" field.
- Install Breeze with
composer require laravel/breeze --dev
- Run
php artisan breeze:install
- Add "phone" column to users migration
- Update registration form view
- Update User model fillable array
- Test registration with the new field
Exercise 2: Implement Custom Authentication
Create a custom login controller without using Breeze that authenticates users by username instead of email.
- Create LoginController with showLoginForm() and login() methods
- Validate username and password fields
- Use Auth::attempt() with username field
- Regenerate session on success
- Redirect to dashboard or return validation errors
- Create corresponding login view
Exercise 3: Multi-Guard Authentication
Set up a multi-guard authentication system with separate guards for regular users and admins.
- Create Admin model and migration
- Add "admin" guard in config/auth.php
- Create admin authentication controller
- Add admin routes protected by auth:admin middleware
- Test login as both user and admin
- Ensure guards don't interfere with each other
Summary
In this lesson, you learned:
- Laravel authentication starter kits (Breeze, Fortify, Jetstream)
- Installing and using Laravel Breeze
- Manual authentication with Auth facade
- Protecting routes with auth middleware
- Accessing authenticated users
- Email verification and password reset
- Authentication guards for multiple user types
- Basic authorization with Gates
Next Lesson: We'll dive deeper into authorization with Policies and learn about middleware customization.