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

cdterry87's avatar

Jetstream/Fortify Two Factor Authentication with Multi-Auth (multiple guards)

Hi Everyone,

I'm working on a new Laravel app with Jetstream/Fortify installed. It will be using a multi-auth setup in which there will be two guards: web (these users will be in a table called users) and admin (these users will be in a table called admins). I've heard that it is generally preferred to have all users in the same table and just assign roles, but that decision isn't up to me so it may not be an option for me to change it.

Both guards are currently setup so both users and admins can login and are redirected to their respective dashboards, so that part is working correctly. Both guards can also update their respective user profiles and update their passwords, so those parts are working correctly also.

The main issue is that I'm having trouble getting the two-factor authentication part working for the admin users. For regular users with the web guard, it is working as expected, so there is not an issue there. For the admin users, though, when they "Enable" two-factor authentication, it updates the two_factor-secret and two_factor_recovery_codes in the admins table correctly, but I'm not sure what to do next to get it to redirect to the two-factor verification screen for admin users when it is enabled.

My Admin LoginController has a typical login method that currently looks like this:

public function login(Request $request)
    {
        $this->validate($request, [
            'email' => 'required|email',
            'password' => 'required|min:6'
        ]);

        if (Auth::guard('admin')->attempt(['email' => $request->email, 'password' => $request->password], $request->remember)) {
            return redirect()->intended(route('admin.dashboard'));
        }
        return back()->withInput($request->only('email', 'remember'));
    }

I know I'm missing some Fortify logic in the code above, I'm just not sure what specifically to add. I did track down in the vendor folder for laravel\fortify that the regular user login is calling the store method and loginPipeline method in AuthenticatedSessionController so I attempted to add that logic into my controller so the login method looks like this instead, but it seems to be checking against the users table instead of the admins table so the user can't even login:

    public function login(LoginRequest $request)
    {
        return $this->loginPipeline($request)->then(function ($request) {
            return app(LoginResponse::class);
        });
    }

    protected function loginPipeline(LoginRequest $request)
    {
        return (new Pipeline(app()))->send($request)->through(array_filter([
            config('fortify.limiters.login') ? null : EnsureLoginIsNotThrottled::class,
            Features::enabled(Features::twoFactorAuthentication()) ? RedirectIfTwoFactorAuthenticatable::class : null,
            AttemptToAuthenticate::class,
            PrepareAuthenticatedSession::class,
        ]));
    }

I appreciate it if anyone has done something like this before and could recommend a solution or point me in the direction of what I might be missing.

Thanks!

EDIT: This also affects the "Enable" and "Disable" two-factor authentication buttons. When I click either of those buttons and it asks to verify the admin's password, it says "This password does not match our records" because I believe it is trying to use the users table instead of the admins table. The enable button does seem to work in the case that I don't have to verify my password, though.

Edit #2: I resolved the issue with my initial edit above regarding the enable/disable buttons. The password confirmation was using the default web guard, but I was able to override it in my FortifyServiceProvider.php by adding the following to the boot() method:

Fortify::confirmPasswordsUsing(function ($user, string $password) {
        return Hash::check($password, $user->password);
    });

Just wanted to leave this here in case it helps anyone else, but I'm still trying to figure out the two-factor authentication on login though.

1 like
1 reply
KiwiCast's avatar

Hey just wanted to let you know that this post helped me out.

I've got a setup using LdapRecord and Jetstream and was also not able to enable 2FA because of ""This password does not match our records"

Your fix resolved my issue. Thank you!

1 like

Please or to participate in this conversation.