Dorokhov.codes

Examples: email verification

If you check events and listeners in your app:

php artisan event:list

you will see that Illuminate\Auth\Listeners\SendEmailVerificationNotification listener is always waiting for the Illuminate\Auth\Events\Registered event.

 Illuminate\Auth\Events\Registered  
  ⇂ Illuminate\Auth\Listeners\SendEmailVerificationNotification  
...

Here’s how this listener looks like:

<?php

namespace Illuminate\Auth\Listeners;

use Illuminate\Auth\Events\Registered;
use Illuminate\Contracts\Auth\MustVerifyEmail;

class SendEmailVerificationNotification
{
    /**
     * Handle the event.
     *
     * @param  \Illuminate\Auth\Events\Registered  $event
     * @return void
     */
    public function handle(Registered $event)
    {
        if ($event->user instanceof MustVerifyEmail && ! $event->user->hasVerifiedEmail()) {
            $event->user->sendEmailVerificationNotification();
        }
    }
}

As you can see, to enable email verification sending, the App\Models\User model should implement the Illuminate\Contracts\Auth\MustVerifyEmail contract.

<?php

namespace App\Models;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;

class User extends Authenticatable implements MustVerifyEmail
{
    use Notifiable;

    // ...
}

Here’s the contract (interface) class:

<?php

namespace Illuminate\Contracts\Auth;

interface MustVerifyEmail
{
    /**
     * Determine if the user has verified their email address.
     *
     * @return bool
     */
    public function hasVerifiedEmail();

    /**
     * Mark the given user's email as verified.
     *
     * @return bool
     */
    public function markEmailAsVerified();

    /**
     * Send the email verification notification.
     *
     * @return void
     */
    public function sendEmailVerificationNotification();

    /**
     * Get the email address that should be used for verification.
     *
     * @return string
     */
    public function getEmailForVerification();
}

These methods are already implemented in the default App\Models\User class (inherited from the parent Illuminate\Foundation\Auth\User class).

There is also a trait for this: Illuminate\Auth\MustVerifyEmail. In fact, it’s used in the Illuminate\Foundation\Auth\User class.

Database Preparation

Your users table must contain an email_verified_at column to store the date and time that the user’s email address was verified.

Routing

To properly implement email verification, three routes will need to be defined.

  • /email/verify: to display a notice to the user that they should click the email verification link in the verification email that Laravel sent them after registration.
  • /email/verify/{id}/{hash}: to handle requests generated when the user clicks the email verification link in the email.
  • /email/verification-notification: to resend a verification link if the user accidentally loses the first verification link.

The Email Verification Notice

Route::get('/email/verify', function () {
    return view('auth.verify-email');
})->middleware('auth')->name('verification.notice');

The verified middleware included with Laravel will automatically redirect to this route name (verification.notice) if a user has not verified their email address.

The Email Verification Handler

Next, we need to define a route that will handle requests generated when the user clicks the email verification link that was emailed to them. This route should be named verification.verify.

use Illuminate\Foundation\Auth\EmailVerificationRequest;

Route::get('/email/verify/{id}/{hash}', function (EmailVerificationRequest $request) {
    $request->fulfill();
    return redirect('/');
})->middleware(['auth', 'signed'])->name('verification.verify');

The form request class Illuminate\Foundation\Auth\EmailVerificationRequest checks parameters and the fulfill() method which does the logic for verification.