Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

lukeboy_2002's avatar

verify mail

In a new laravel site/ app with starter kit the registration is not what I expect. After registration, the user must register his email. So in My model I added MustVerifyMail. After registering, the https://{mysite}/verify-email page will be loaded. You can choose to log out or resend verification mail. The email comes in. but can only work in the open browser where you have not yet logged out. If you are logged out, the link will not work and you will go back to the login page. the email_verified_at is not entered in the database.

The routes auth.php contain the routes linked to the middleware auth.

Route::get('verify-email/{id}/{hash}', VerifyEmailController::class)->middleware(['signed', 'throttle:6,1'])->name('verification.verify');

and

Route::get('verify-email', EmailVerificationPromptController::class)->name('verification.notice');

How can I make it so that verification is possible even if the user is already logged out or is using a different browser.

1 like
5 replies
vincent15000's avatar

What you want is not the normal behavior.

If you really want this, I suggest you to generate your own temporary email verification link and handle the verification by your own in a controller.

ghabriel25's avatar

I think there was a video from Jeffrey about passwordless authentication

1 like
imrandevbd's avatar

This happens because the starter kits (Breeze/Jetstream) wrap that verification route in the auth middleware by default. When you open the link in a different browser, you're a "guest," so the middleware intercepts the request and redirects you to the login page before the verification logic even runs.

To fix this, you need to allow guests to hit that endpoint and manually find the user since $request->user() won't be available.

First, in routes/auth.php, move the route outside the auth middleware group, Then, you'll need to tweak the VerifyEmailController. Since you aren't using the auth middleware anymore,

1 like
LaryAI's avatar
Level 58

Certainly! Here's a detailed solution for your Laracasts question, explaining both the cause and the way to allow email verification even if the user is logged out or using a different browser.


Problem Explanation

By default, Laravel's email verification requires the user to be authenticated (logged in) to verify their email. This is enforced by the auth middleware on the route:

Route::get('verify-email/{id}/{hash}', VerifyEmailController::class)
    ->middleware(['auth', 'signed', 'throttle:6,1'])
    ->name('verification.verify');

If the user is not logged in, visiting the verification link simply redirects to the login page, and email_verified_at won't get updated.

This behavior is a security choice, but often users expect to be able to verify from a new device, browser, or after logging out.


Solution: Remove the auth Middleware

To allow verification without requiring the user to be logged in, remove the auth middleware from your verification route, keeping the signed middleware for security. The signed middleware ensures the link can’t be tampered with.

Change your route in routes/web.php or routes/auth.php to:

Route::get('verify-email/{id}/{hash}', VerifyEmailController::class)
    ->middleware(['signed', 'throttle:6,1']) // removed 'auth'
    ->name('verification.verify');

But Wait—Now What about Verification Logic?

By default, your VerifyEmailController may reference auth()->user(). If the user is not logged in, auth()->user() will be null. Instead, you can retrieve the user by the ID in the route, and manually mark their email as verified.

Here's a simple custom controller as an example:

use Illuminate\Http\Request;
use App\Models\User;
use Illuminate\Auth\Events\Verified;
use Illuminate\Support\Facades\Auth;

public function __invoke(Request $request, $id, $hash)
{
    $user = User::findOrFail($id);

    if (! hash_equals((string) $hash, sha1($user->getEmailForVerification()))) {
        abort(403, 'Invalid verification link');
    }

    if (! $user->hasVerifiedEmail()) {
        $user->markEmailAsVerified();
        event(new Verified($user));
    }

    // Optionally, log in the user or redirect with message.
    // Auth::login($user); // Uncomment to log them in automatically

    return redirect('/login')->with('status', 'Your email has been verified! You can now login.');
}

This is similar to how Laravel does it under the hood, except it does not require the logged-in session.


Final Tips

  • Resend Verification: Users will still need to log in to request another verification email, since that route will usually require authentication.
  • Security: Keeping signed in the middleware is crucial, as it ensures the link can't be manipulated.
  • Customization: You can automatically log the user in upon verification, or just redirect with a success message.

Summary

  1. Remove 'auth' from the verification route middleware.
  2. In your controller, fetch the user by ID, check the hash, and mark as verified.
  3. Keep signed and throttle middleware for security.

Example Route and Controller

// In routes/web.php or auth.php
Route::get('verify-email/{id}/{hash}', 'App\Http\Controllers\Auth\CustomVerifyEmailController')
    ->middleware(['signed', 'throttle:6,1'])
    ->name('verification.verify');
// In app/Http/Controllers/Auth/CustomVerifyEmailController.php
namespace App\Http\Controllers\Auth;

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

class CustomVerifyEmailController extends Controller
{
    public function __invoke(Request $request, $id, $hash)
    {
        $user = User::findOrFail($id);

        if (! hash_equals((string) $hash, sha1($user->getEmailForVerification()))) {
            abort(403, 'Invalid verification link');
        }

        if (! $user->hasVerifiedEmail()) {
            $user->markEmailAsVerified();
            event(new Verified($user));
        }

        // Optionally, log the user in:
        // Auth::login($user);

        return redirect('/login')->with('status', 'Your email has been verified! Please log in.');
    }
}

This will let users verify their email from any browser, even if they are not logged in.

Let me know if you need a ready-to-use controller stub or any more help!

Please or to participate in this conversation.