Implementing Email verification in Laravel API application

44 Views Asked by At

I have a Laravel application that acts as a backend API for the VueJS frontend. I have overwritten the handle method of the EnsureEmailIsVerified middle in order to have the frontend handle redirection.

The problem I am facing has to do with the /mail/send-verification route which is behind the auth middleware to get the user. The registration process returns access and refresh tokens for the frontend to be able to call /mail/send-verification. In the case where the user registers and tries to login before verifying their email, the backend returns a 403 "Your email address is not verified." which prevents the frontend from being able to call send-verification since it doesn't have a the access token.

Route::post('/email/send-verification', [VerificationController::class, 'send'])->middleware('auth:api');

What approach should I take to resolve this? Is there a better way to implement the registration email verification process?

1

There are 1 best solutions below

0
EHF Shahab On

First you need to create a custom notification. Second you need controller for requesting verification and confirmation code. Thired a model and table row for saving vcodes

In my case custom email verification trough api requests done like this: path: app/Notifications/apiEmailVerification.php

<?php

namespace App\Notifications;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
use App\Models\User;
use App\Models\ApiEmailVerification as AEV;

class apiEmailVerification extends Notification
{
use Queueable;

/**
* Create a new notification instance.
*
* @return void     
*/

public function __construct()
{
//
}

/**
* Get the notification's delivery channels.
*
* @param  mixed  $notifiable
* @return array
*/
public function via($notifiable)
{
return ['mail'];
}

/**
* Get the mail representation of the notification.
*
* @param  mixed  $notifiable
* @return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
$user_id = $notifiable->id;
$vcode = mt_rand(11111,99999);

AEV::updateOrCreate(['user_id' => $user_id], ['evcode' => $vcode]);

return (new MailMessage())
->subject('your subject')
->line('some text')
->action('Notification Action', url('/your-url'))
->line($vcode);
}

/**
* Get the array representation of the notification.
*
* @param  mixed  $notifiable
* @return array
*/
public function toArray($notifiable)
{
return [
//
];
}
}

now email verification controller to send verification code by mail to user's email: for example EmailVerificationController.php

<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Notifications\apiEmailVerification as emailApiVerification;
use App\Models\User;

class EmailVerificationController extends Controller
{
    
    public function update(Request $request, $id)
      {  
        $user = User::where('id', $id)->first();        
        
        if($user != null)
          {
        $user->notify(new emailApiVerification()); 
           
        return response()->json(['status' => 1, 'message' => 'Code successfully sent to user email!'], 200);
        } else {
        return response()->json(['status' => 0, 'message' => 'Code not sent, user not found!'], 404); 
        }               
     }
}

and EmailConfirmationController.php

    <?php
    
    namespace App\Http\Controllers\Api;
    
    use App\Http\Controllers\Controller;
    use Illuminate\Http\Request;
    use App\Models\ApiEmailVerification;
    use App\Models\User;
    
    class EmailConfirmationController extends Controller
    {
        
        public function update(Request $request, $id)
          {
             if($request->has('evcode'))
              {         
                               
            $DbEvcode = ApiEmailVerification::where('user_id', $id)->first();               
            $DBCode = $DbEvcode->evcode;               
             
            if($DBCode == $request->evcode)
                {
            User::where('id', $id)->update(['email_verified_at' => now()]);
                 
return response()->json(['status' => 1, 'message' => 'Email successfully confirmed!'], 200);
               } else {             
return response()->json(['status' => 0, 'message' => 'Email not confirmed!'], 406);
               }        
           }      
        }
    }

a model for email verification is necessary:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class ApiEmailVerification extends Model
{
    protected $guarded = [];
    protected $table = 'api_email_verification';
    protected $fillable=['user_id', 'evcode'];
 
    public function user()
    {
        return $this->belongsTo('App\Models\User', 'user_id');
    }
}

This is just an example. You probably need to add some functions for displaying forms, hashing codes or etc related to your website situation and needs.