hasChallengedUser() || $this->challengeHasExpired($request)) { $this->clearChallenge($request); return redirect()->route('login'); } return Inertia::render('Auth/TwoFactorChallenge'); } /** * Complete the pending login using a TOTP or recovery code. */ public function store( TwoFactorLoginRequest $request, SecurityEventRecorder $securityEvents ): RedirectResponse { if (! config('auth-ui.features.two_factor') || ! $request->hasChallengedUser() || $this->challengeHasExpired($request)) { $this->clearChallenge($request); return redirect()->route('login'); } $user = $request->challengedUser(); if (! $user->hasEnabledTwoFactorAuthentication()) { $this->clearChallenge($request); return redirect()->route('login'); } if ($recoveryCode = $request->validRecoveryCode()) { $user->replaceRecoveryCode($recoveryCode); } elseif (! $request->hasValidCode()) { event(new TwoFactorAuthenticationFailed($user)); $user->notify(new TwoFactorFailedNotification( (string) $request->ip(), (string) $request->userAgent(), now()->toIso8601String() )); $securityEvents->record('login.two_factor_failed', $user, $request); throw ValidationException::withMessages([ $request->filled('recovery_code') ? 'recovery_code' : 'code' => 'The provided authentication code was invalid.', ]); } event(new ValidTwoFactorAuthenticationCodeProvided($user)); Auth::login($user, $request->remember()); $request->session()->regenerate(); $securityEvents->record('login.two_factor_succeeded', $user, $request, [ 'used_recovery_code' => (bool) $recoveryCode, ]); return redirect()->intended(config('auth-ui.redirects.login', '/dashboard')); } private function clearChallenge(TwoFactorLoginRequest $request): void { $request->session()->forget(['login.id', 'login.remember', 'login.started_at']); } private function challengeHasExpired(TwoFactorLoginRequest $request): bool { $startedAt = $request->session()->get('login.started_at'); return ! is_int($startedAt) || now()->timestamp - $startedAt > config('auth-ui.security.two_factor_challenge_timeout'); } }