From fdd9b56c683131db6fb2bf980618f64efe960365 Mon Sep 17 00:00:00 2001 From: Duncan McClean Date: Mon, 16 Mar 2026 12:13:33 +0000 Subject: [PATCH] Ability to disable two-factor authentication --- config/users.php | 12 ++++++++++++ src/Auth/User.php | 8 ++++++++ .../Controllers/CP/Users/UsersController.php | 2 +- tests/Auth/UserContractTests.php | 17 +++++++++++++++++ 4 files changed, 38 insertions(+), 1 deletion(-) diff --git a/config/users.php b/config/users.php index b0c9b2e7a0f..70e266eb280 100644 --- a/config/users.php +++ b/config/users.php @@ -181,6 +181,18 @@ 'elevated_session_duration' => 15, + /* + |-------------------------------------------------------------------------- + | Two-Factor Authentication + |-------------------------------------------------------------------------- + | + | Here you may disable two-factor authentication entirely. This can be + | useful on local or staging environments, or when using OAuth. + | + */ + + 'two_factor_enabled' => env('STATAMIC_TWO_FACTOR_ENABLED', true), + /* |-------------------------------------------------------------------------- | Enforce Two-Factor Authentication diff --git a/src/Auth/User.php b/src/Auth/User.php index c16f0db698e..96d3287b677 100644 --- a/src/Auth/User.php +++ b/src/Auth/User.php @@ -365,6 +365,10 @@ public function preferredColorMode() public function isTwoFactorAuthenticationRequired(): bool { + if (! config('statamic.users.two_factor_enabled', true)) { + return false; + } + $enforcedRoles = config('statamic.users.two_factor_enforced_roles', []); if (in_array('*', $enforcedRoles)) { @@ -383,6 +387,10 @@ public function isTwoFactorAuthenticationRequired(): bool */ public function hasEnabledTwoFactorAuthentication(): bool { + if (! config('statamic.users.two_factor_enabled', true)) { + return false; + } + return ! is_null($this->two_factor_secret) && ! is_null($this->two_factor_confirmed_at); } diff --git a/src/Http/Controllers/CP/Users/UsersController.php b/src/Http/Controllers/CP/Users/UsersController.php index d83f2108770..08ffecf564b 100644 --- a/src/Http/Controllers/CP/Users/UsersController.php +++ b/src/Http/Controllers/CP/Users/UsersController.php @@ -277,7 +277,7 @@ public function edit(Request $request, $user) 'canEditPassword' => User::fromUser($request->user())->can('editPassword', $user), 'requiresCurrentPassword' => $isCurrentUser = $request->user()->id === $user->id(), 'itemActions' => Action::for($user, ['view' => 'form']), - 'twoFactor' => $isCurrentUser ? [ + 'twoFactor' => $isCurrentUser && config('statamic.users.two_factor_enabled', true) ? [ 'isEnforced' => $user->isTwoFactorAuthenticationRequired(), 'wasSetup' => $user->hasEnabledTwoFactorAuthentication(), 'routes' => [ diff --git a/tests/Auth/UserContractTests.php b/tests/Auth/UserContractTests.php index 724af5aa1ae..436d9d3b271 100644 --- a/tests/Auth/UserContractTests.php +++ b/tests/Auth/UserContractTests.php @@ -669,6 +669,23 @@ public function it_determines_if_the_user_has_enabled_two_factor_authentication( $this->assertTrue($user->hasEnabledTwoFactorAuthentication()); } + #[Test] + public function it_returns_false_for_two_factor_methods_when_disabled() + { + config()->set('statamic.users.two_factor_enabled', false); + config()->set('statamic.users.two_factor_enforced_roles', ['*']); + + $user = $this->makeUser() + ->makeSuper() + ->set('two_factor_secret', 'secret') + ->set('two_factor_confirmed_at', now()->timestamp); + + $user->save(); + + $this->assertFalse($user->hasEnabledTwoFactorAuthentication()); + $this->assertFalse($user->isTwoFactorAuthenticationRequired()); + } + #[Test] public function it_gets_recovery_codes() {