Now Reading
Email Verification System when using Laravel Sanctum
Dark Light

Email Verification System when using Laravel Sanctum

email verification using laravel sanctum

In one of my previous post I have shared some scripts on adding Logging in and Registering a user functionality in Laravel. We all know Laravel has a great advantage of authentication coz all the needed functionalities that we need to have in an login system is already available. But since we are using custom API using sanctum then we might also need to create custom ones for other functionalities.

So here we are going to add email verification functionalities and soon I will also add forget password and reset password functionalities. We will be using Laravel default methods customised to work on our API.

Lets start with User Model:

use Laravel\Sanctum\HasApiTokens;
use Illuminate\Contracts\Auth\MustVerifyEmail;

class User extends Authenticatable implements MustVerifyEmail
{
    use HasApiTokens, Notifiable;
}

Add the MustVerifyEmail interface so some methods that are need for email validation will be ready.

Next Add two Traits which I took from Laravel Auth Package in the folder
Http/Controllers/Auth/Traits
Make sure the directory is correct for composer to autoload classes correctly.

In this folder first we are going to add the file RedirectsUsers.php . This files is not much necessary but some might need this to do some manual changes so that he have much control over what he is developing. As I have said already I am going to use most of the Laravel Auth Package files itself in a customised way.

Here is the code for RedirectsUsers.php

<?php

namespace App\Http\Controllers\Auth\Traits;

trait RedirectsUsers
{
    /**
     * Get the post register / login redirect path.
     *
     * @return string
     */
    public function redirectPath()
    {
        if (method_exists($this, 'redirectTo')) {
            return $this->redirectTo();
        }

        return property_exists($this, 'redirectTo') ? $this->redirectTo : '/home';
    }
}

Next create another trait in the same directory Http/Controllers/Auth/Traits with the name VerifiesEmails.php

The code for VerifiesEmails.php

<?php

namespace App\Http\Controllers\Auth\Traits;

use App\Models\User;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Auth\Events\Verified;
use Illuminate\Http\Request;

trait VerifiesEmails
{
    use RedirectsUsers;

    /**
     * Show the email verification notice.
     *
     * @param \Illuminate\Http\Request $request
     * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Http\RedirectResponse|\Illuminate\Http\Response|\Illuminate\Routing\Redirector
     */
    public function show(Request $request)
    {
        return $request->user()->hasVerifiedEmail() ? redirect($this->redirectPath()) : view('auth.verify');
    }

    /**
     * Mark the authenticated user's email address as verified
     * @param Request $request
     * @param User $id
     * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
     * @throws AuthorizationException
     */
    public function verify(Request $request,User $id)
    {
        if ($id->hasVerifiedEmail()) {
            return response()->json([
                'verified' => true,
                'message' => 'Email Verified Already'
            ]);
        }

        if ($id->markEmailAsVerified()) {
            event(new Verified($id));
        }

        return response()->json([
            'verified' => true,
        ]);
    }

    /**
     * Resend the email verification notification.
     *
     * @param \Illuminate\Http\Request $request
     */
    public function resend(Request $request)
    {
        if ($request->user()->hasVerifiedEmail()) {
            return response()->json([
               'verified' => true,
               'message' => 'Email Verified Already'
            ]);
        }

        $request->user()->sendEmailVerificationNotification();

        return response()->json([
            'verified' => false,
            'resent' => true,
            'message' => 'Verification Email sent again'
        ]);
    }
}

Now comes the controller for managing the requests. Lets create a controller called VerificationController.php using artisan commands

php artisan make:controller Auth\\VerificationController

Now add the code for the controller

<?php

namespace App\Http\Controllers\Auth\Traits;

use App\Models\User;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Auth\Events\Verified;
use Illuminate\Http\Request;

trait VerifiesEmails
{
    use RedirectsUsers;

    /**
     * Show the email verification notice.
     *
     * @param \Illuminate\Http\Request $request
     * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Http\RedirectResponse|\Illuminate\Http\Response|\Illuminate\Routing\Redirector
     */
    public function show(Request $request)
    {
        return $request->user()->hasVerifiedEmail() ? redirect($this->redirectPath()) : view('auth.verify');
    }

    /**
     * Mark the authenticated user's email address as verified
     * @param Request $request
     * @param User $id
     * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
     * @throws AuthorizationException
     */
    public function verify(Request $request,User $id)
    {
        if ($id->hasVerifiedEmail()) {
            return response()->json([
                'verified' => true,
                'message' => 'Email Verified Already'
            ]);
        }

        if ($id->markEmailAsVerified()) {
            event(new Verified($id));
        }

        return response()->json([
            'verified' => true,
        ]);
    }

    /**
     * Resend the email verification notification.
     *
     * @param \Illuminate\Http\Request $request
     */
    public function resend(Request $request)
    {
        if ($request->user()->hasVerifiedEmail()) {
            return response()->json([
               'verified' => true,
               'message' => 'Email Verified Already'
            ]);
        }

        $request->user()->sendEmailVerificationNotification();

        return response()->json([
            'verified' => false,
            'resent' => true,
            'message' => 'Verification Email sent again'
        ]);
    }
}

Thats are we are almost done. Final steps is to add only the end points to make request. So open api.php in the routes folder and add the below lines.

Route::get('email/verify/{id}/{hash}', 'Auth\VerificationController@verify')->name('verification.verify');
Route::group(['middleware' => 'auth:sanctum'], function () {

    Route::post('email/resend', 'Auth\VerificationController@resend')->name('verification.resend');
 });

With this all the functionalities for have email verification with resend email verification is also added. If you have any questions kindly add it in the comments below.

Bonus:

See Also
changing mysql 8 root password

I could see when you are using verified middleware in the api routes it is responding based on Laravel default middleware. So let’s make it a managed one.

php artisan make:middleware EnsureMailIsVerified

Now edit the middleware and add the following code:

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Support\Facades\Redirect;

class EnsureMailIsVerified
{
    /**
     * Handle an incoming request.
     *
     * @param \Illuminate\Http\Request $request
     * @param \Closure $next
     * @return mixed
     */
    public function handle($request, Closure $next, $redirectToRoute = null)
    {
        if (!$request->user() || ($request->user() instanceof MustVerifyEmail && !$request->user()->hasVerifiedEmail())) {
            return $request->expectsJson() ? response()->json([
                'message' => 'Your email address is not verified.'
            ], 403) : Redirect::route($redirectToRoute ?: 'verification.notice');
        }
        return $next($request);
    }
}

Finally update the middleware in the kernel file in the directory app\Http\Kernel.php

change the file used for the *verified* middleware to \App\Http\Middleware\EnsureMailIsVerified

With this complete email verification is complete.
We have a forum where you can share your dev queries for help.
Thanks for reading.

Happy Coding.
#stayhome #staysafe

View Comments (0)

Leave a Reply

Your email address will not be published.

Scroll To Top