# Install Breeze for ready-made login/register/password reset
composer require laravel/breeze --dev
php artisan breeze:install blade # Blade + Tailwind
# or:
php artisan breeze:install vue # with Vue/Inertia
php artisan breeze:install api # API tokens only
npm install && npm run dev
php artisan migrate
# Gives you: Login, Register, Password Reset, Email Verify
# Routes in: routes/auth.php
# Views in: resources/views/auth/
3. Manual Auth Controller
// app/Http/Controllers/Auth/LoginController.php
class LoginController extends Controller
{
public function showLogin()
{
return view('auth.login');
}
public function login(Request $request)
{
$credentials = $request->validate([
'email' => ['required', 'email'],
'password' => ['required'],
]);
if (Auth::attempt($credentials, $request->boolean('remember'))) {
$request->session()->regenerate(); // prevent session fixation
return redirect()->intended(route('dashboard'));
}
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('/');
}
}
4. Protect Routes with Middleware
// routes/web.php
// Option 1: Middleware on route group
Route::middleware('auth')->group(function () {
Route::resource('posts', PostController::class);
Route::get('/dashboard', [DashboardController::class, 'index'])
->name('dashboard');
});
// Option 2: Multiple middleware
Route::middleware(['auth', 'verified']) // verified = email verified
->group(function () { /* ... */ });
// Option 3: Named middlewares
Route::middleware(['auth', 'role:admin'])->group(/* ... */);
// In controller constructor
class PostController extends Controller
{
public function __construct()
{
$this->middleware('auth');
$this->middleware('auth')->only(['store', 'update', 'destroy']);
$this->middleware('guest')->only(['create']);
}
}
5. Auth Facade — Current User
use Illuminate\Support\Facades\Auth;
// Check login status
Auth::check() // true if logged in
Auth::guest() // true if NOT logged in
// Get current user
$user = Auth::user() // User model instance (null if guest)
$id = Auth::id() // just the ID (null if guest)
// Helper functions (same thing)
$user = auth()->user()
$id = auth()->id()
// In Blade templates
@auth
<p>Welcome, {{ auth()->user()->name }}!</p>
<a href="{{ route('logout') }}">Logout</a>
@endauth
@guest
<a href="{{ route('login') }}">Login</a>
<a href="{{ route('register') }}">Register</a>
@endguest
// Only show if user owns the post
@if(auth()->id() === $post->user_id)
<a href="{{ route('posts.edit', $post) }}">Edit</a>
@endif
6. Policies — Authorization Per Model
# Generate a policy
php artisan make:policy PostPolicy --model=Post
// app/Policies/PostPolicy.php
class PostPolicy
{
public function viewAny(User $user): bool
{
return true; // anyone can list posts
}
public function view(?User $user, Post $post): bool
{
return true; // ? = can be guest
}
public function create(User $user): bool
{
return true; // any logged-in user
}
public function update(User $user, Post $post): bool
{
return $user->id === $post->user_id // only owner
|| $user->isAdmin(); // or admin
}
public function delete(User $user, Post $post): bool
{
return $user->id === $post->user_id || $user->isAdmin();
}
}
// Register in AuthServiceProvider (Laravel 10) or auto-discovered (11+)
// Use in controller
public function edit(Post $post)
{
$this->authorize('update', $post); // 403 if denied
return view('posts.edit', compact('post'));
}
// Or with can()
if (auth()->user()->can('update', $post)) {
// show edit button
}
// In Blade
@can('update', $post)
<a href="{{ route('posts.edit', $post) }}">Edit</a>
@endcan
@cannot('delete', $post)
<p>(read-only)</p>
@endcannot
7. Custom Middleware
# Generate middleware
php artisan make:middleware EnsureUserIsAdmin
// app/Http/Middleware/EnsureUserIsAdmin.php
class EnsureUserIsAdmin
{
public function handle(Request $request, Closure $next): Response
{
if (!auth()->check() || !auth()->user()->is_admin) {
abort(403, 'Admin access required');
}
return $next($request); // pass request through
}
}
// Register in bootstrap/app.php (Laravel 11+)
->withMiddleware(function (Middleware $middleware) {
$middleware->alias([
'admin' => EnsureUserIsAdmin::class,
]);
})
// Use on routes
Route::middleware(['auth', 'admin'])->group(function () {
Route::get('/admin', [AdminController::class, 'index']);
});
8. Login Throttle (Rate Limiting)
// Laravel Breeze / built-in auth already includes throttle:6,1
// But for manual controllers, add to routes:
Route::post('/login', [LoginController::class, 'login'])
->middleware('throttle:10,1'); // 10 attempts per minute
// Or use RateLimiter in a service:
use Illuminate\Support\Facades\RateLimiter;
$key = 'login.' . Str::lower($email) . '|' . $request->ip();
if (RateLimiter::tooManyAttempts($key, 5)) {
$seconds = RateLimiter::availableIn($key);
return back()->withErrors([
'email' => "Too many attempts. Try again in {$seconds}s."
]);
}
RateLimiter::hit($key, 60); // record attempt, expire in 60s
// ... attempt auth ...
RateLimiter::clear($key); // clear on success