Complete Laravel Authentication Setup with Breeze

Introduction

Complete Laravel Authentication Setup with Breeze

A Comprehensive Guide to Modern Authentication in Laravel Applications

Laravel Breeze is a minimal, simple implementation of all Laravel’s authentication features. It provides a great starting point for building Laravel applications with authentication, including login, registration, password reset, email verification, and profile management. Unlike Jetstream, which offers more features with teams and API support, Breeze focuses on the essentials with beautifully designed Blade templates. In this comprehensive guide, we’ll walk through everything you need to know to set up, customize, and extend Laravel Breeze for your projects.


Getting Started with Laravel Breeze

Installation and initial setup of Laravel Breeze

Installation Process

Start by creating a fresh Laravel project and installing Breeze with your preferred stack (Blade, React, or Vue).

Terminal Commands

# Create a new Laravel project
laravel new breeze-app
cd breeze-app

# Install Breeze with Blade stack (default)
composer require laravel/breeze --dev
php artisan breeze:install

# For React stack
php artisan breeze:install react

# For Vue stack
php artisan breeze:install vue

# Install npm dependencies and compile assets
npm install
npm run dev

# Run migrations
php artisan migrate

# Serve the application
php artisan serve

Breeze Directory Structure

After installation, Breeze creates several files and directories. Here’s what you get:

Breeze File Structure

app/
├── Http/Controllers/
│   ├── Auth/
│   │   ├── AuthenticatedSessionController.php
│   │   ├── ConfirmablePasswordController.php
│   │   ├── EmailVerificationNotificationController.php
│   │   ├── EmailVerificationPromptController.php
│   │   ├── NewPasswordController.php
│   │   ├── PasswordController.php
│   │   ├── PasswordResetLinkController.php
│   │   ├── ProfileController.php
│   │   └── RegisteredUserController.php
│   └── Controller.php
├── View/Components/
│   ├── AppLayout.php
│   └── GuestLayout.php
└── Models/User.php

resources/
├── css/
│   └── app.css
├── js/
│   ├── app.js
│   └── bootstrap.js
└── views/
    ├── auth/
    │   ├── confirm-password.blade.php
    │   ├── forgot-password.blade.php
    │   ├── login.blade.php
    │   ├── register.blade.php
    │   ├── reset-password.blade.php
    │   └── verify-email.blade.php
    ├── components/
    │   └── ...
    ├── dashboard.blade.php
    ├── layout/
    │   ├── app.blade.php
    │   └── guest.blade.php
    └── profile/
        └── edit.blade.php

routes/
└── auth.php # Authentication routes

Authentication Controllers

Registration Controller

The registration controller handles new user creation with validation and automatic login.

RegisteredUserController.php

<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\Models\User;
use App\Providers\RouteServiceProvider;
use Illuminate\Auth\Events\Registered;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\Rules;

class RegisteredUserController extends Controller
{
    /**
     * Display the registration view.
     */
    public function create()
    {
        return view('auth.register');
    }

    /**
     * Handle an incoming registration request.
     */
    public function store(Request $request)
    {
        $request->validate([
            'name' => ['required', 'string', 'max:255'],
            'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
            'password' => ['required', 'confirmed', Rules\Password::defaults()],
        ]);

        $user = User::create([
            'name' => $request->name,
            'email' => $request->email,
            'password' => Hash::make($request->password),
        ]);

        event(new Registered($user));

        Auth::login($user);

        return redirect(RouteServiceProvider::HOME);
    }
}

Login Controller

The login controller handles user authentication with session management.


Customizing Breeze

Adding Additional Fields to Registration

Extend the default registration form to include additional user fields.

Extended RegisteredUserController.php

<?php

namespace App\Http\Controllers\Auth;

use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Validation\Rules;

class RegisteredUserController extends Controller
{
    public function store(Request $request)
    {
        // Extended validation with additional fields
        $validated = $request->validate([
            'first_name' => ['required', 'string', 'max:100'],
            'last_name' => ['required', 'string', 'max:100'],
            'username' => ['required', 'string', 'max:50', 'unique:users'],
            'phone' => ['nullable', 'string', 'max:20'],
            'date_of_birth' => ['nullable', 'date'],
            'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
            'password' => ['required', 'confirmed', Rules\Password::defaults()],
            'terms' => ['required', 'accepted'],
        ]);

        // Create user with additional fields
        $user = User::create([
            'first_name' => $validated['first_name'],
            'last_name' => $validated['last_name'],
            'name' => $validated['first_name'] . ' ' . $validated['last_name'],
            'username' => $validated['username'],
            'email' => $validated['email'],
            'phone' => $validated['phone'] ?? null,
            'date_of_birth' => $validated['date_of_birth'] ?? null,
            'password' => Hash::make($validated['password']),
            'email_verified_at' => now(), // Auto-verify for demo, remove for production
        ]);

        event(new Registered($user));
        Auth::login($user);

        return redirect(RouteServiceProvider::HOME)
            ->with('success', 'Registration successful! Welcome to our platform.');
    }
}

Custom Blade Registration Form

@extends('layout.guest')

@section('content')
    <div class="min-h-screen flex flex-col sm:justify-center items-center pt-6 sm:pt-0 bg-gray-100">
        <div class="w-full sm:max-w-2xl mt-6 px-6 py-8 bg-white shadow-md overflow-hidden sm:rounded-lg">
            <form method="POST" action="{{ route('register') }}">
                @csrf

                <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
                    <!-- First Name -->
                    <div>
                        <label for="first_name" class="block font-medium text-sm text-gray-700">
                            First Name
                        </label>
                        <input id="first_name" class="block mt-1 w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500"
                               type="text" name="first_name" value="{{ old('first_name') }}" required autofocus autocomplete="given-name">
                        @error('first_name')
                        <div class="text-red-600 text-sm mt-1">{{ $message }}</div>
                        @enderror
                    </div>

                    <!-- Last Name -->
                    <div>
                        <label for="last_name" class="block font-medium text-sm text-gray-700">
                            Last Name
                        </label>
                        <input id="last_name" class="block mt-1 w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500"
                               type="text" name="last_name" value="{{ old('last_name') }}" required autocomplete="family-name">
                        @error('last_name')
                        <div class="text-red-600 text-sm mt-1">{{ $message }}</div>
                        @enderror
                    </div>
                </div>

                <!-- Continue with other fields (email, password, etc.) -->
                <!-- ... -->

                <div class="flex items-center justify-end mt-6">
                    <a class="underline text-sm text-gray-600 hover:text-gray-900" href="{{ route('login') }}">
                        Already registered?
                    </a>

                    <button type="submit"
                            class="ml-4 inline-flex items-center px-4 py-2 bg-indigo-600 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-indigo-700 focus:bg-indigo-700 active:bg-indigo-900 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 transition ease-in-out duration-150">
                        Register
                    </button>
                </div>
            </form>
        </div>
    </div>
@endsection


Advanced Breeze Features

Email Verification Setup

# Enable email verification in User model
class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable, MustVerifyEmail;
    // ...
}

# Update auth routes to require verification
Route::get('/dashboard', function () {
    return view('dashboard');
})->middleware(['auth', 'verified'])->name('dashboard');

# Configure mail settings in .env
MAIL_MAILER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=your_username
MAIL_PASSWORD=your_password
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS="noreply@example.com"
MAIL_FROM_NAME="Your App Name"

Password Reset Configuration

# Password reset routes (already included in Breeze)
Route::get('forgot-password', [PasswordResetLinkController::class, 'create'])
    ->middleware('guest')
    ->name('password.request');

Route::post('forgot-password', [PasswordResetLinkController::class, 'store'])
    ->middleware('guest')
    ->name('password.email');

Route::get('reset-password/{token}', [NewPasswordController::class, 'create'])
    ->middleware('guest')
    ->name('password.reset');

Route::post('reset-password', [NewPasswordController::class, 'store'])
    ->middleware('guest')
    ->name('password.update');


Testing Breeze Authentication

<?php

namespace Tests\Feature\Auth;

use App\Models\User;
use Illuminate\Auth\Notifications\ResetPassword;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Notification;
use Tests\TestCase;

class AuthenticationTest extends TestCase
{
    use RefreshDatabase;

    // Test registration
    public function test_users_can_register()
    {
        $response = $this->post('/register', [
            'name' => 'Test User',
            'email' => 'test@example.com',
            'password' => 'password',
            'password_confirmation' => 'password',
        ]);

        $this->assertAuthenticated();
        $response->assertRedirect(RouteServiceProvider::HOME);
    }

    // Test login
    public function test_users_can_login()
    {
        $user = User::factory()->create();

        $response = $this->post('/login', [
            'email' => $user->email,
            'password' => 'password',
        ]);

        $this->assertAuthenticated();
        $response->assertRedirect(RouteServiceProvider::HOME);
    }

    // Test password reset
    public function test_password_reset_link_can_be_requested()
    {
        Notification::fake();
        $user = User::factory()->create();

        $this->post('/forgot-password', [
            'email' => $user->email,
        ]);

        Notification::assertSentTo($user, ResetPassword::class);
    }
}


Conclusion

Laravel Breeze provides a perfect starting point for authentication in Laravel applications.

With its minimal approach, beautiful Blade templates, and comprehensive feature set, Breeze allows developers to quickly set up authentication without the complexity of larger packages like Jetstream. Whether you’re building a simple application or a complex system, Breeze provides the foundation you need with room for customization and extension.

Key Takeaways:

    • Breeze is perfect for projects that need authentication without additional complexity

    • Choose between Blade, React, or Vue.js stacks based on your frontend preferences.

 

What is Laravel Breeze and when should I use it?

Laravel Breeze is a minimal, simple implementation of Laravel’s authentication features. Use it when you need a clean, straightforward authentication system without the additional complexity of packages like Jetstream.

Leave a Reply

Your email address will not be published. Required fields are marked *