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

SILENT's avatar

Laravel Fortify 2FA middleware

Hello all,

I want to create a middleware for my routes to only allow access to users with 2FA enabled. I want to understand a bit more on how the fortify 2FA works, is the 2FA challenge only for the single session or can a user click remember me and return without needing to do the 2FA challenge again? Is there somewhere I can read up easily on the entire chain? I basically want to give the user a view to see their recovery codes after the fact but for safety insure that they did do the 2FA recently as to prevent session highjacking and steeling the recovery codes.

0 likes
12 replies
SILENT's avatar

Thank you sadly $15 is expensive for me. I will attempt to figure it out on my own.

1 like
vincent15000's avatar

@SILENT You have several free examples on the web, but be careful to choose one which uses the best practices.

SILENT's avatar

So I have done some testing on my site and see that it is doing exactly what I don't want. If a user logs in and clicks remember me, then enters 2FA code. They can return to the site as much as they like, this is perfect and expected behavior, however I would like to have some routes have the user enter 2FA if they access it (unless the recently used 2FA) much like the confirm password does in the fortify docs (https://laravel.com/docs/10.x/fortify#password-confirmation) but instead a 2FA confirmation before allowing a user to proceed to the protected URL. Any suggestions on a method? I wanted to check the two_factor_confirmed_at field and do a time comparison but if I redirect the user to the auth.two-factor-challenge page then it just allows the user through without presenting them with the 2FA challenge. Any suggestions on how I should proceed would be greatly appreciated. Basically I want to invalidate the 2FA session while still keeping the user logged in forcing them to redo the 2FA challenge.

1 like
SILENT's avatar

@vincent15000 As I said I would like to create some kind of middleware that functions exactly like the password-confirmation challenge. It's all to add an extra layer of security to routes as to ensure that the person accessing it is indeed the intended user.

1 like
wojakmcwagies's avatar

@SILENT Wait I don't think I get it, but what you want is something like below?

  • User go to login page
  • User input email and password
  • User enter 2FA code
  • User logged in and redirected to index page
  • When a user wants to go to another page, they need to enter 2FA again?

Because if that's what you want, it's not the best idea. It's overkill and going to make your users frustrated because they need to do 2FA over and over again. Remember, you need to take into account about User Experience too when creating a web or an app.

A better, secure, while not making your users frustrated is to implement a lock screen. Basically, if the user is detected to be idle for a period of time, when they need to do something, redirect it to a lock screen page where they need to enter their password (but no 2FA) and then they can proceed again.

Basically, you only do the 2FA ONCE for every session. Unless the user closes their browser or doesn't check Remember Me.

SILENT's avatar

Sorry for the late reply @wojakmcwagies. I think I have explained terribly so I will attempt to explain using code, below is a mockup of my 2FA middleware:

public function handle($request, Closure $next)
{
    $user = $request->user();

    if ($user && $user->two_factor_completed_at) {
        // Check if the user completed 2FA in the past 10 minutes
        $completedAt = $user->two_factor_completed_at;

        if ($completedAt && now()->diffInMinutes($completedAt) <= 10) {
            return $next($request);
        }
		else
		{
			// Invalidate the 2FA session then redirect the user to the 2FA challenge page
		}
    }

    return redirect()->route('auth.two-factor-challenge');
}

Hopefully this makes a bit more sense. Was also thinking of adding in a session variable to ensure that the 2FA challenge was completed during the current active session and not by a returning user. I don't want to make it harder for a user to use the site but basically want to add extra security to ensure any destructive/harmful routes are protected by a 2FA challenge ie. view 2FA recovery codes, delete account, change recovery email address.

SILENT's avatar

Any chance somone can please assist me with this. I have been trying to read the code and follow how it works to better understand what I need to do to accomplish what I am looking to do however I have not had any luck

Snapey's avatar

@SILENT perhaps first modify the existing code to add a token in session when 2FA is used successfully. There might be an event for that

Then the route that you want to verify 2fa before access can check the session and see if the token is set. If not then the user came in via a remembered login, and you can redirect them to a 2fa challenge

SILENT's avatar

@Snapey Thank you that sounds like a good idea. Will most likely need to just change the challenge section of the code as if I look at the source code, there is TwoFactorAuthenticationEvent and TwoFactorAuthenticationChallenged and I could modify these events to set a session variable to state that the user was challenged in this session.

Snapey's avatar

@SILENT You can't modify anything in the vendor folder, but you can add a listener that listens for TwoFactorAuthenticationEvent

Please or to participate in this conversation.