Skip to content

Commit adb4c73

Browse files
committed
adding 2fa challenge controller
1 parent e5c8b58 commit adb4c73

File tree

1 file changed

+112
-0
lines changed

1 file changed

+112
-0
lines changed
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
<?php
2+
3+
namespace App\Http\Controllers\Auth;
4+
5+
use App\Actions\TwoFactorAuth\CompleteTwoFactorAuthentication;
6+
use App\Actions\TwoFactorAuth\ProcessRecoveryCode;
7+
use App\Http\Controllers\Controller;
8+
use App\Models\User;
9+
use Illuminate\Http\Request;
10+
use Illuminate\Support\Facades\Auth;
11+
use Inertia\Inertia;
12+
13+
14+
class TwoFactorAuthChallengeController extends Controller
15+
{
16+
/**
17+
* Display the two factor authentication challenge view.
18+
*
19+
* @param \Illuminate\Http\Request $request
20+
* @return \Inertia\Response
21+
*/
22+
public function create(Request $request)
23+
{
24+
// Session check is now handled by the EnsureTwoFactorChallengeSession middleware
25+
return Inertia::render('auth/two-factor-challenge');
26+
}
27+
28+
/**
29+
* Attempt to authenticate a new session using the two factor authentication code.
30+
*
31+
* @param \Illuminate\Http\Request $request
32+
* @return mixed
33+
*/
34+
public function store(Request $request)
35+
{
36+
$request->validate([
37+
'code' => 'nullable|string',
38+
'recovery_code' => 'nullable|string',
39+
]);
40+
41+
// If we made it here, user is available via the EnsureTwoFactorChallengeSession middleware
42+
$user = $request->two_factor_auth_user;
43+
44+
// Handle one-time password (OTP) code
45+
if ($request->filled('code')) {
46+
return $this->authenticateUsingCode($request, $user);
47+
}
48+
49+
// Handle recovery code
50+
if ($request->filled('recovery_code')) {
51+
return $this->authenticateUsingRecoveryCode($request, $user);
52+
}
53+
54+
return back()->withErrors(['code' => __('Please provide a valid two factor code.')]);
55+
}
56+
57+
/**
58+
* Authenticate using a one-time password (OTP).
59+
*
60+
* @param \Illuminate\Http\Request $request
61+
* @param \App\Models\User $user
62+
* @return \Illuminate\Http\Response
63+
*/
64+
protected function authenticateUsingCode(Request $request, User $user)
65+
{
66+
$secret = decrypt($user->two_factor_secret);
67+
$valid = app(\App\Actions\TwoFactorAuth\VerifyTwoFactorCode::class)($secret, $request->code);
68+
69+
if ($valid) {
70+
app(CompleteTwoFactorAuthentication::class)($user);
71+
return redirect()->intended(route('dashboard', absolute: false));
72+
}
73+
74+
return back()->withErrors(['code' => __('The provided two factor authentication code was invalid.')]);
75+
}
76+
77+
/**
78+
* Authenticate using a recovery code.
79+
*
80+
* @param \Illuminate\Http\Request $request
81+
* @param \App\Models\User $user
82+
* @return \Illuminate\Http\Response
83+
*/
84+
protected function authenticateUsingRecoveryCode(Request $request, User $user)
85+
{
86+
$recoveryCodes = json_decode(decrypt($user->two_factor_recovery_codes), true);
87+
$provided = $request->recovery_code;
88+
$match = collect($recoveryCodes)->first(function ($code) use ($provided) {
89+
return hash_equals($code, $provided);
90+
});
91+
92+
if (! $match) {
93+
return back()->withErrors(['recovery_code' => __('The provided two factor authentication recovery code was invalid.')]);
94+
}
95+
96+
// Remove used recovery code using the ProcessRecoveryCode action
97+
$updatedCodes = app(ProcessRecoveryCode::class)($recoveryCodes, $match);
98+
if ($updatedCodes === false) {
99+
return back()->withErrors(['recovery_code' => __('The provided two factor authentication recovery code was invalid.')]);
100+
}
101+
102+
$user->two_factor_recovery_codes = encrypt(json_encode($updatedCodes));
103+
$user->save();
104+
105+
// Complete the authentication process
106+
app(CompleteTwoFactorAuthentication::class)($user);
107+
108+
// Redirect to the intended page
109+
return redirect()->intended(route('dashboard', absolute: false));
110+
}
111+
}
112+

0 commit comments

Comments
 (0)