4

I implemented MustVerifyEmail interface in my user model

class User extends Authenticatable implements MustVerifyEmail

also I made VerificationApi Controller

<?php

namespace App\Http\Controllers;

use App\Models\User;
use Illuminate\Foundation\Auth\VerifiesEmails;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Auth\Events\Verified;

class VerificationApiController extends Controller
{
    use VerifiesEmails;

    * Mark the authenticated user’s email address as verified.

    *

    * @param \Illuminate\Http\Request $request

    * @return \Illuminate\Http\Response

    */

    public function verify(Request $request) {

    $userID = $request['id'];

    $user = User::findOrFail($userID);

    $date = date("Y-m-d H:i:s");

    $user->email_verified_at = $date; // to enable the “email_verified_at field of that user be a current time stamp by mimicing the must verify email feature

    $user->save();

    return response()->json('Email verified!');

    }

    /**

    * Resend the email verification notification.

    *

    * @param \Illuminate\Http\Request $request

    * @return \Illuminate\Http\Response

    */

    public function resend(Request $request)

    {

    if ($request->user()->hasVerifiedEmail()) {

    return response()->json('User already have verified email!', 422);

    // return redirect($this->redirectPath());

    }

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

    return response()->json('The notification has been resubmitted');

    }
}

and I made

<?php

namespace App\Notifications;

use Illuminate\Support\Carbon;

use Illuminate\Support\Facades\URL;

use Illuminate\Auth\Notifications\VerifyEmail as VerifyEmailBase;

class VerifyApiEmail extends VerifyEmailBase

{

/**

* Get the verification URL for the given notifiable.

*

* @param mixed $notifiable

* @return string

*/

protected function verificationUrl($notifiable)

{

return URL::temporarySignedRoute(

'verificationapi.verify', Carbon::now()->addMinutes(60), ['id' => $notifiable->getKey()]

); // this will basically mimic the email endpoint with get request

}

}

in my api.php file I added

Route::get('email/verify/{id}', 'VerificationApiController@verify')->name('verificationapi.verify');

Route::get('email/resend', 'VerificationApiController@resend')->name('verificationapi.resend');

So when i register to my api I get verification email in my mailtrap and when I click the button it says that my email is verified and in my database it changes from null to email_verified_at 2019-05-27 13:04:20 but when I put middleware('verified') on my routes and when I login with user that I have registrated in my postman I get


    "message": "Your email address is not verified.",
    "exception": "Symfony\\Component\\HttpKernel\\Exception\\HttpException",

my register() and login() functions look like this:

 public function register(Request $request, User $user)
    {
        $phoneRegex = "(06|387)[0-9]{7,8}";
        $request->validate([
            'first_name' => 'required|string',
            'last_name' => 'required|string',
            'email' => 'required|string|email|unique:users',
            'password' => 'required|string|confirmed',
            'phone_number' => 'required|string|min:6',

        ]);
        $user = new User([
            'first_name' => $request->first_name,
            'last_name' => $request->last_name,
            'email' => $request->email,
            'password' => bcrypt($request->password),
            'phone_number' => $request['phone_number'],
        ]);
        $user->save();

            Auth::login($user,true);
            $user->sendApiEmailVerificationNotification();

            $success['message'] = 'Please confirm yourself by clicking on verify user button sent to you on your email';

            return response()->json(['success'=>$success], $this->successStatus);
}
public function login(Request $request)
    {
        $request->request->add([
            'client_id' => env("PASSPORT_CLIENT_ID"),
            'client_secret' => env("PASSPORT_CLIENT_SECRET"),
            'grant_type' => 'password',
            'scope' => '',
        ]);
        $tokenRequest = $request->create('/oauth/token', 'POST', $request->all());
        $response = Route::dispatch($tokenRequest);

        return $response;
    }

can someone help me with this?

Leona
  • 73
  • 3
  • 10

2 Answers2

1

I solved this by doing the following:

Create a file

Http > Middleware > EnsureEmailIsVerified.php

with this code

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Contracts\Auth\Factory as Auth;

class EnsureEmailIsVerified
{
    /**
     * The authentication factory instance.
     *
     * @var \Illuminate\Contracts\Auth\Factory
     */
    protected $auth;

    /**
     * Create a new middleware instance.
     *
     * @param  \Illuminate\Contracts\Auth\Factory  $auth
     * @return void
     */
    public function __construct(Auth $auth)
    {
        $this->auth = $auth;
    }

    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @param  string|null  $redirectToRoute
     * @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
     */
    public function handle($request, Closure $next, $guard = null)
    {
        if (! $request->user($guard)) {
            if($request->expectsJson()) {
                return response()->json([
                    'message' => 'You do not have permission to access this feature.',
                    'errors' => [
                        'main' => ['The access token is either missing or incorrect.']
                    ]
                ], 401);
            } else {
                return redirect(route('login'));
            }
        } else if
            ($request->user($guard) instanceof MustVerifyEmail &&
            ! $request->user($guard)->hasVerifiedEmail()) {

            if($request->expectsJson()) {
                return response()->json([
                    'message' => 'You do not have permission to access this feature.',
                    'errors' => [
                        'main' => ['Your email address is not verified.']
                    ]
                ], 403);
            } else {
                return redirect(route('verification.notice'));
            }
        }

        $this->auth->shouldUse($guard);

        return $next($request);
    }
}

In the Kernel.php file, change the value for 'verified'

protected $routeMiddleware = [
    ...
    'verified' => \App\Http\Middleware\EnsureEmailIsVerified::class,
]

In the routes > api.php file use verified:api

Route::group(['middleware' => 'verified:api'], function () {
    Route::get('/user', function (Request $request)    {
        return $request->user();
    });
});

This works well for me, as I can use the same middleware for both my API and website while still being as generic as possible.

salmanhijazi
  • 817
  • 2
  • 13
  • 25
0

I just added this to my login() function and now it looks like this

public function login(Request $request)
    {
        $request->request->add([
            'client_id' => env("PASSPORT_CLIENT_ID"),
            'client_secret' => env("PASSPORT_CLIENT_SECRET"),
            'grant_type' => 'password',
            'scope' => '',
        ]);
        $tokenRequest = $request->create('/oauth/token', 'POST', $request->all());
        $response = Route::dispatch($tokenRequest);

        $user = User::where('email', $request->username)->first();

        if($user->email_verified_at !== NULL){
            $success['message'] = "Login successfull";
            return $response;
            }else{
            return response()->json(['error'=>'Please Verify Email'], 401);
            }
    }

and now if you did not verify your email you can't login it does not give you your access and refresh token back but I don't have to use my middleware('verified') on my routes so if someone still have better solution I would appreciate it.

Leona
  • 73
  • 3
  • 10