What changed, and why it matters
This commit removes the 2FA recovery-code feature from BTCPay Server. Recovery codes are normally printed when you enable two-factor authentication and used as a backup way to log in if you lose your phone. After this change, users can no longer create or use those codes. The commit does not add a replacement backup login path, so anyone who loses access to their authenticator app may be permanently locked out of their account unless they have another login method configured. The change is presented as a feature removal, not as a fix for a specific security bug.
Treat this as a product/security change requiring review. Verify whether an alternative account-recovery method (e.g., FIDO2 backup credentials, admin reset, or email reset) is documented and functional. If no replacement exists, consider warning users before deployment and updating documentation. If the removal was intended to address a vulnerability in recovery-code handling, request a security advisory or CVE from the project.
Security signals we found
Removal of account-recovery mechanism without replacement
Reduced resilience of 2FA authentication flow
Potential increase in account lockout risk for users relying on TOTP authenticator
No explicit security bug described in commit message or diff
Evidence from the diff
The patch deletes the recovery-code generation, display, and redemption flows. Removed: LoginWithRecoveryCode GET/POST actions in UIAccountController, GenerateRecoveryCodes GET/POST actions in UIManageController.Authenticator, the associated view models (LoginWithRecoveryCodeViewModel, GenerateRecoveryCodesViewModel), the RecoveryCodesLeft property on TwoFactorAuthenticationViewModel, the recovery-code .cshtml views, and related translation strings. The authenticator login action was also slightly refactored: ModelState validity check was removed and the TwoFactorCode is now null-coalesced. The commit is titled “Remove recovery codes” and contains no explanation of a vulnerability or incident.
Changed components
BTCPayServer/Controllers/UIAccountController.csBTCPayServer/Controllers/UIManageController.Authenticator.csBTCPayServer/Controllers/UIManageController.csBTCPayServer/Views/UIAccount/LoginWithAuthenticator.cshtmlBTCPayServer/Views/UIAccount/LoginWithRecoveryCode.cshtmlBTCPayServer/Views/UIManage/GenerateRecoveryCodes.cshtmlBTCPayServer/Views/UIManage/TwoFactorAuthentication.cshtmlInspect captured patch +7 / −218
diff --git a/BTCPayServer.Tests/GlobalSearchTests.cs b/BTCPayServer.Tests/GlobalSearchTests.cs
index 9398cae..50ddb87 100644
--- a/BTCPayServer.Tests/GlobalSearchTests.cs
+++ b/BTCPayServer.Tests/GlobalSearchTests.cs
@@ -22,9 +22,9 @@ public class GlobalSearchTests(ITestOutputHelper helper) : UnitTestBase(helper)
await s.StartAsync();
await s.RegisterNewUser(isAdmin: true);
await s.CreateNewStore();
-
await s.GlobalSearch.GoToPage("Setup wallet");
await s.Page.WaitForURLAsync(s.ServerUri + $"stores/{s.StoreId}/onchain/BTC");
+
var admin = (s.CreatedUser, s.Password);
// Create a new invoice and check that you can search for it either via invoice id, bitcoin address or transaction id.
diff --git a/BTCPayServer.Tests/PMO/GlobalSearchPMO.cs b/BTCPayServer.Tests/PMO/GlobalSearchPMO.cs
index 2d2942c..6f955c0 100644
--- a/BTCPayServer.Tests/PMO/GlobalSearchPMO.cs
+++ b/BTCPayServer.Tests/PMO/GlobalSearchPMO.cs
@@ -13,6 +13,7 @@ public class GlobalSearchPMO(PlaywrightTester tester)
/// <param name="page"></param>
public async Task GoToPage(string page)
{
+ await Page.Locator("#globalSearchInput").WaitForAsync();
await Page.Keyboard.PressAsync("/");
await Page.Keyboard.TypeAsync(page);
await Page.Keyboard.PressAsync("Enter");
diff --git a/BTCPayServer.Tests/PayJoinTests.cs b/BTCPayServer.Tests/PayJoinTests.cs
index 4a180b4..db444fe 100644
--- a/BTCPayServer.Tests/PayJoinTests.cs
+++ b/BTCPayServer.Tests/PayJoinTests.cs
@@ -271,7 +271,6 @@ namespace BTCPayServer.Tests
});
await AssertDestinationFilled(s, bip21);
await s.Page.FillAsync("#Outputs_0__Amount", "0.023");
- await s.TakeScreenshot("filled.png");
await s.Page.ClickAsync("#SignTransaction");
await s.Server.WaitForEvent<NewOnChainTransactionEvent>(async () =>
{
@@ -281,7 +280,7 @@ namespace BTCPayServer.Tests
}
catch
{
- await s.TakeScreenshot("Flaky.png");
+ await s.TakeScreenshot("PayJoinTests-Flaky.png");
throw;
}
});
diff --git a/BTCPayServer/Controllers/UIAccountController.cs b/BTCPayServer/Controllers/UIAccountController.cs
index 5f1ece1..0cadce2 100644
--- a/BTCPayServer/Controllers/UIAccountController.cs
+++ b/BTCPayServer/Controllers/UIAccountController.cs
@@ -457,20 +457,13 @@ namespace BTCPayServer.Controllers
{
return RedirectToAction("Login");
}
-
- if (!ModelState.IsValid)
- {
- return View(model);
- }
if (user.IsDisabledTemporarily)
return LockoutView(user);
var session = LoginSession.Load(HttpContext.Session);
- var authenticatorCode = model.TwoFactorCode.Replace(" ", string.Empty, StringComparison.InvariantCulture)
+ var authenticatorCode = (model?.TwoFactorCode ?? "") .Replace(" ", string.Empty, StringComparison.InvariantCulture)
.Replace("-", string.Empty, StringComparison.InvariantCulture);
- // TwoFactorAuthenticatorSignInAsync
- //signInManager.TwoFactorAuthenticatorSignInAsync()
var success = await userManager.VerifyTwoFactorTokenAsync(user, signInManager.Options.Tokens.AuthenticatorTokenProvider, authenticatorCode);
if (success)
{
@@ -512,46 +505,6 @@ namespace BTCPayServer.Controllers
return RedirectToLocal(session.ReturnUrl);
}
- [HttpGet("/login/recovery-code")]
- [AllowAnonymous]
- public IActionResult LoginWithRecoveryCode()
- {
- if (!CanLoginOrRegister())
- return RedirectToAction("Login");
- return View();
- }
-
- [HttpPost("/login/recovery-code")]
- [AllowAnonymous]
- [ValidateAntiForgeryToken]
- public async Task<IActionResult> LoginWithRecoveryCode(LoginWithRecoveryCodeViewModel model)
- {
- var user = await signInManager.GetTwoFactorAuthenticationUserAsync();
- var session = UIAccountController.LoginSession.Load(HttpContext.Session);
- if (!CanLoginOrRegister() || user is null || session is null)
- {
- return RedirectToAction("Login");
- }
-
- if (!ModelState.IsValid)
- {
- return View(model);
- }
-
- if (user.IsDisabledTemporarily)
- return LockoutView(user);
-
- var recoveryCode = model.RecoveryCode.Trim().Split(' ').FirstOrDefault() ?? "";
- var result = await userManager.RedeemTwoFactorRecoveryCodeAsync(user, recoveryCode);
- if (result.Succeeded)
- {
- return await RedirectLoginSuccess(user, session);
- }
- await userManager.AccessFailedAsync(user);
- ModelState.AddModelError(nameof(model.RecoveryCode), "Invalid recovery code entered.");
- return View(model);
- }
-
private IActionResult LockoutView(ApplicationUser user) => View("Lockout", user);
[HttpGet("/register")]
diff --git a/BTCPayServer/Controllers/UIManageController.Authenticator.cs b/BTCPayServer/Controllers/UIManageController.Authenticator.cs
index 1968c88..567ea92 100644
--- a/BTCPayServer/Controllers/UIManageController.Authenticator.cs
+++ b/BTCPayServer/Controllers/UIManageController.Authenticator.cs
@@ -1,6 +1,5 @@
using System;
using System.Globalization;
-using System.Linq;
using System.Text;
using System.Threading.Tasks;
using BTCPayServer.Abstractions.Extensions;
@@ -13,7 +12,6 @@ namespace BTCPayServer.Controllers
{
public partial class UIManageController
{
- private const string RecoveryCodesKey = nameof(RecoveryCodesKey);
private const string AuthenicatorUriFormat = "otpauth://totp/{0}:{1}?secret={2}&issuer={0}&digits=6";
[HttpGet]
@@ -60,10 +58,7 @@ namespace BTCPayServer.Controllers
await _userManager.UpdateAsync(user);
TempData.SetStatusSuccess(StringLocalizer["Authenticator enabled successfully."]);
- var recoveryCodes = await _userManager.GenerateNewTwoFactorRecoveryCodesAsync(user, 10);
- TempData[RecoveryCodesKey] = recoveryCodes.ToArray();
-
- return RedirectToAction(nameof(GenerateRecoveryCodes));
+ return RedirectToAction(nameof(TwoFactorAuthentication));
}
[HttpPost]
@@ -79,35 +74,6 @@ namespace BTCPayServer.Controllers
return RedirectToAction(nameof(EnableAuthenticator));
}
- [HttpPost]
- [ActionName(nameof(GenerateRecoveryCodes))]
- public async Task<IActionResult> GenerateRecoveryCodesPost()
- {
- var user = await _userManager.GetUserAsync(User);
- if (user is null)
- return NotFound();
- var recoveryCodes = await _userManager.GenerateNewTwoFactorRecoveryCodesAsync(user, 10);
- TempData[RecoveryCodesKey] = recoveryCodes.ToArray();
- return RedirectToAction(nameof(GenerateRecoveryCodes));
- }
-
- [HttpGet]
- public IActionResult GenerateRecoveryCodes()
- {
- if (TempData[RecoveryCodesKey] is string[] recoveryCodes)
- {
- var model = new GenerateRecoveryCodesViewModel { RecoveryCodes = recoveryCodes };
- return View(model);
- }
-
- return View("Confirm", new ConfirmModel(
- title: StringLocalizer["Generate new recovery codes"],
- desc: StringLocalizer["This action will generate new recovery codes for your account. Please confirm to proceed."],
- action: StringLocalizer["Generate"],
- buttonClass: "btn-primary"
- ));
- }
-
private string GenerateQrCodeUri(string email, string unformattedKey)
{
return string.Format(CultureInfo.InvariantCulture,
diff --git a/BTCPayServer/Controllers/UIManageController.cs b/BTCPayServer/Controllers/UIManageController.cs
index 4035fa0..9f66e32 100644
--- a/BTCPayServer/Controllers/UIManageController.cs
+++ b/BTCPayServer/Controllers/UIManageController.cs
@@ -110,7 +110,6 @@ namespace BTCPayServer.Controllers
var model = new TwoFactorAuthenticationViewModel
{
IsAuthenticatorEnabled = await _userManager.IsAuthenticatorConfigured(user),
- RecoveryCodesLeft = await _userManager.CountRecoveryCodesAsync(user),
Credentials = await _fido2Service.GetCredentials(user.Id)
};
diff --git a/BTCPayServer/Models/AccountViewModels/LoginWithRecoveryCodeViewModel.cs b/BTCPayServer/Models/AccountViewModels/LoginWithRecoveryCodeViewModel.cs
deleted file mode 100644
index 14d5f2a..0000000
--- a/BTCPayServer/Models/AccountViewModels/LoginWithRecoveryCodeViewModel.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-using System.ComponentModel.DataAnnotations;
-
-namespace BTCPayServer.Models.AccountViewModels
-{
- public class LoginWithRecoveryCodeViewModel
- {
- [Required]
- [DataType(DataType.Text)]
- [Display(Name = "Recovery Code")]
- public string RecoveryCode { get; set; }
- }
-}
diff --git a/BTCPayServer/Models/ManageViewModels/GenerateRecoveryCodesViewModel.cs b/BTCPayServer/Models/ManageViewModels/GenerateRecoveryCodesViewModel.cs
deleted file mode 100644
index 77e7356..0000000
--- a/BTCPayServer/Models/ManageViewModels/GenerateRecoveryCodesViewModel.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-namespace BTCPayServer.Models.ManageViewModels
-{
- public class GenerateRecoveryCodesViewModel
- {
- public string[] RecoveryCodes { get; set; }
- }
-}
diff --git a/BTCPayServer/Models/ManageViewModels/TwoFactorAuthenticationViewModel.cs b/BTCPayServer/Models/ManageViewModels/TwoFactorAuthenticationViewModel.cs
index 73ce5e8..4350691 100644
--- a/BTCPayServer/Models/ManageViewModels/TwoFactorAuthenticationViewModel.cs
+++ b/BTCPayServer/Models/ManageViewModels/TwoFactorAuthenticationViewModel.cs
@@ -6,8 +6,6 @@ namespace BTCPayServer.Models.ManageViewModels
public class TwoFactorAuthenticationViewModel
{
- public int RecoveryCodesLeft { get; set; }
-
public bool IsAuthenticatorEnabled { get; set; }
public List<Fido2Credential> Credentials { get; set; }
diff --git a/BTCPayServer/Plugins/Translations/Translations.Default.cs b/BTCPayServer/Plugins/Translations/Translations.Default.cs
index 0a3c61c..c3f1e95 100644
--- a/BTCPayServer/Plugins/Translations/Translations.Default.cs
+++ b/BTCPayServer/Plugins/Translations/Translations.Default.cs
@@ -736,7 +736,6 @@ namespace BTCPayServer.Plugins.Translations
"Generate another address": "",
"Generate API Key": "",
"Generate Key": "",
- "Generate new recovery codes": "",
"Generated Code": "",
"Get Link": "",
"Give other registered BTCPay Server users access to your store. See the {0} for granted permissions.": "",
@@ -774,7 +773,6 @@ namespace BTCPayServer.Plugins.Translations
"HTML Meta Tags": "",
"HTTP-based Tor hidden services": "",
"I have written down my recovery phrase and stored it in a secure location": "",
- "I wrote down my recovery codes": "",
"Id": "",
"ID": "",
"If a translation isn’t available, it will be searched in the fallback.": "",
@@ -786,7 +784,6 @@ namespace BTCPayServer.Plugins.Translations
"If you do not understand the above, go with the defaults and start scanning.": "",
"If you lose it or write it down incorrectly, you may permanently lose access to your funds.": "",
"If you lose it or write it down incorrectly, you will permanently lose access to your funds.": "",
- "If you lose your device and don't have the recovery codes you will lose access to your account.": "",
"If your LND REST server is using HTTP or HTTPS with an untrusted certificate, you can set\n <code>allowinsecure=true</code> as a fallback.": "",
"If your security device has a button, tap on it.": "",
"Image": "",
@@ -1309,8 +1306,6 @@ namespace BTCPayServer.Plugins.Translations
"Recommendation ({0})": "",
"Recommended": "",
"Recommended fee confirmation target blocks": "",
- "Recovery Code": "",
- "Recovery codes": "",
"Recurring": "",
"Recurring Goal": "",
"Recurring Type": "",
@@ -1323,7 +1318,6 @@ namespace BTCPayServer.Plugins.Translations
"Refund {0}": "",
"Refunds Issued": "",
"Regenerate": "",
- "Regenerate your 2FA recovery codes.": "",
"Register": "",
"Register Device": "",
"Register page redirect URL": "",
@@ -1381,7 +1375,6 @@ namespace BTCPayServer.Plugins.Translations
"Reset goal after a specific period of time, based on your crowdfund's start date.": "",
"Reset goal every": "",
"Reset Password": "",
- "Reset recovery codes": "",
"Reset your password": "",
"Resetting Boltcard...": "",
"Resources": "",
@@ -1785,7 +1778,6 @@ namespace BTCPayServer.Plugins.Translations
"This account has been locked out. Please try again": "",
"This action is permanent and will remove the ability to change the SSH settings via the BTCPay Server user interface.": "",
"This action will delete your rate script. Are you sure to turn off rate rules scripting?": "",
- "This action will generate new recovery codes for your account. Please confirm to proceed.": "",
"This action will modify your current rate sources. Are you sure to turn on rate rules scripting? (Advanced users)": "",
"This action will permanently delete your LND seed and password. You will not be able to recover them if you don't have a backup.": "",
"This action will permanently delete your LND seed and password. You will not be able to recover them if you don't have a backup. Are you sure?": "",
@@ -1830,7 +1822,7 @@ namespace BTCPayServer.Plugins.Translations
"This page is served in non-secure context (HTTPS, localhost or file://)": "",
"This payment method requires javascript.": "",
"This permission is not available for your account.": "",
- "This process disables 2FA until you verify your authenticator app and will also reset your 2FA recovery codes. If you do not complete your authenticator app configuration you may lose access to your account.": "",
+ "This process disables 2FA until you verify your authenticator app. If you do not complete your authenticator app configuration you may lose access to your account.": "",
"This processor cannot handle {0}.": "",
"This pull payment does not exists": "",
"This QR Code is only valid for 10 minutes": "",
@@ -2084,8 +2076,6 @@ namespace BTCPayServer.Plugins.Translations
"You currently have no stores configured.": "",
"You do not have a local username/password for this site. Add a local account so you can log in without an external login.": "",
"You do not have the permissions to change this settings": "",
- "You have no recovery codes left.": "",
- "You have requested to log in with a recovery code. This login will not be remembered until you provide an authenticator app code at login or disable 2FA and log in again.": "",
"You have successfully signed out.": "",
"You must enable at least one payment method before creating a payout.": "",
"You must enable at least one payment method before creating a pull payment.": "",
@@ -2097,7 +2087,6 @@ namespace BTCPayServer.Plugins.Translations
"You need to select a store before creating an invoice.": "",
"You need to select a store first": "",
"You need to update your version of NBXplorer": "",
- "You only have 1 recovery code left.": "",
"You really should not type your seed into a device that is connected to the internet.": "",
"Your access to BTCPay Server is over an unsecured network. If you are using the docker deployment method with NGINX and HTTPS is not available, you probably did not configure your DNS settings correctly. We disabled the register and login link so you don't leak your credentials.": "",
"Your account has been disabled. Please contact server administrator.": "",
@@ -2110,7 +2099,6 @@ namespace BTCPayServer.Plugins.Translations
"Your email has been confirmed.": "",
"Your email has been confirmed. Please set your password.": "",
"Your email server has not been configured.": "",
- "Your existing recovery codes will no longer be valid!": "",
"Your instance administrator has disabled the use of the Internal node for non-admin users.": "",
"Your node address: {0}": "",
"Your password has been changed.": "",
diff --git a/BTCPayServer/Views/UIAccount/LoginWithAuthenticator.cshtml b/BTCPayServer/Views/UIAccount/LoginWithAuthenticator.cshtml
index 6fb7908..7e1e501 100644
--- a/BTCPayServer/Views/UIAccount/LoginWithAuthenticator.cshtml
+++ b/BTCPayServer/Views/UIAccount/LoginWithAuthenticator.cshtml
@@ -16,9 +16,4 @@
<button type="submit" class="btn btn-primary" text-translate="true">Log in</button>
</div>
</form>
- <p class="text-secondary mt-4 mb-0">
- Don't have access to your authenticator device?
- <br>
- You can <a asp-action="LoginWithRecoveryCode">log in with a recovery code</a>.
- </p>
</div>
diff --git a/BTCPayServer/Views/UIAccount/LoginWithRecoveryCode.cshtml b/BTCPayServer/Views/UIAccount/LoginWithRecoveryCode.cshtml
deleted file mode 100644
index 74d809b..0000000
--- a/BTCPayServer/Views/UIAccount/LoginWithRecoveryCode.cshtml
+++ /dev/null
@@ -1,19 +0,0 @@
-@model LoginWithRecoveryCodeViewModel
-@{
- Layout = "_LayoutSignedOut";
- ViewData["Title"] = "Recovery code verification";
-}
-
-<p text-translate="true">You have requested to log in with a recovery code. This login will not be remembered until you provide an authenticator app code at login or disable authenticator and log in again.</p>
-<form method="post">
- <div class="form-group">
- <label asp-for="RecoveryCode" class="form-label"></label>
- <input asp-for="RecoveryCode" class="form-control" autocomplete="off" />
- <span asp-validation-for="RecoveryCode" class="text-danger"></span>
- </div>
- <button type="submit" class="btn btn-primary" text-translate="true">Log in</button>
-</form>
-
-@section PageFootContent {
- <partial name="_ValidationScriptsPartial" />
-}
diff --git a/BTCPayServer/Views/UIManage/GenerateRecoveryCodes.cshtml b/BTCPayServer/Views/UIManage/GenerateRecoveryCodes.cshtml
deleted file mode 100644
index 5d63c8e..0000000
--- a/BTCPayServer/Views/UIManage/GenerateRecoveryCodes.cshtml
+++ /dev/null
@@ -1,31 +0,0 @@
-@model GenerateRecoveryCodesViewModel
-@{
- ViewData.SetLayoutModel(new LayoutModel(nameof(ManageNavPages.TwoFactorAuthentication), StringLocalizer["Recovery codes"])
- .SetCategory(nameof(ManageNavPages)));
-}
-
-<h2 class="mb-2 mb-lg-3">@ViewData["Title"]</h2>
-<partial name="_StatusMessage" />
-
-<div class="alert alert-warning" role="alert">
- <h5>
- <vc:icon symbol="warning" />
- <span text-translate="true">Put these codes in a safe place</span>
- </h5>
- <p class="mb-0" text-translate="true">
- If you lose your device and don't have the recovery codes you will lose access to your account.
- </p>
-</div>
-<div class="row">
- <div class="col-md-12">
- @for(var row = 0; row < Model.RecoveryCodes.Length; row += 2)
- {
- <code>@Model.RecoveryCodes[row]</code><text> </text><code>@Model.RecoveryCodes[row + 1]</code><br />
- }
- </div>
-</div>
-<div class="row mt-4">
- <div class="col-md-12">
- <a asp-action="TwoFactorAuthentication" class="btn btn-primary" text-translate="true">I wrote down my recovery codes</a>
- </div>
-</div>
diff --git a/BTCPayServer/Views/UIManage/TwoFactorAuthentication.cshtml b/BTCPayServer/Views/UIManage/TwoFactorAuthentication.cshtml
index 49e63c9..6ad890e 100644
--- a/BTCPayServer/Views/UIManage/TwoFactorAuthentication.cshtml
+++ b/BTCPayServer/Views/UIManage/TwoFactorAuthentication.cshtml
@@ -14,51 +14,10 @@
<h4 class="mb-3" text-translate="true">Authenticator</h4>
- @if (Model.IsAuthenticatorEnabled)
- {
- if (Model.RecoveryCodesLeft == 0)
- {
- <div class="alert alert-danger">
- <h4 class="alert-heading mb-3">
- <vc:icon symbol="warning" />
- <span text-translate="true">You have no recovery codes left.</span>
- </h4>
- <p class="mb-0">You must <a asp-action="GenerateRecoveryCodes" class="alert-link">generate a new set of recovery codes</a> before you can log in with a recovery code.</p>
- </div>
- }
- else if (Model.RecoveryCodesLeft == 1)
- {
- <div class="alert alert-danger">
- <h4 class="alert-heading mb-3">
- <vc:icon symbol="warning" />
- <span text-translate="true">You only have 1 recovery code left.</span>
- </h4>
- <p class="mb-0">You can <a asp-action="GenerateRecoveryCodes" class="alert-link">generate a new set of recovery codes</a>.</p>
- </div>
- }
- else if (Model.RecoveryCodesLeft <= 3)
- {
- <div class="alert alert-warning">
- <h4 class="alert-heading mb-3">
- <vc:icon symbol="warning" />
- You only have @Model.RecoveryCodesLeft recovery codes left.
- </h4>
- <p class="mb-0">You should <a asp-action="GenerateRecoveryCodes" class="alert-link">generate a new set of recovery codes</a>.</p>
- </div>
- }
- }
-
<div class="list-group mb-3">
@if (Model.IsAuthenticatorEnabled)
{
- <a asp-action="GenerateRecoveryCodes" class="list-group-item d-flex justify-content-between align-items-center list-group-item-action py-3" data-bs-toggle="modal" data-bs-target="#ConfirmModal" data-title="@StringLocalizer["Reset recovery codes"]" data-description="@StringLocalizer["Your existing recovery codes will no longer be valid!"]" data-confirm="@StringLocalizer["Reset"]" data-confirm-input="@StringLocalizer["RESET"]">
- <div>
- <h5 text-translate="true">Reset recovery codes</h5>
- <p class="mb-0 me-3" text-translate="true">Regenerate your 2FA recovery codes.</p>
- </div>
- <vc:icon symbol="caret-right"/>
- </a>
- <a asp-action="ResetAuthenticator" class="list-group-item d-flex justify-content-between align-items-center list-group-item-action py-3" data-bs-toggle="modal" data-bs-target="#ConfirmModal" data-title="@StringLocalizer["Reset authenticator app"]" data-description="@StringLocalizer["This process disables 2FA until you verify your authenticator app and will also reset your 2FA recovery codes. If you do not complete your authenticator app configuration you may lose access to your account."]" data-confirm="@StringLocalizer["Reset"]" data-confirm-input="@StringLocalizer["RESET"]">
+ <a asp-action="ResetAuthenticator" class="list-group-item d-flex justify-content-between align-items-center list-group-item-action py-3" data-bs-toggle="modal" data-bs-target="#ConfirmModal" data-title="@StringLocalizer["Reset authenticator app"]" data-description="@StringLocalizer["This process disables 2FA until you verify your authenticator app. If you do not complete your authenticator app configuration you may lose access to your account."]" data-confirm="@StringLocalizer["Reset"]" data-confirm-input="@StringLocalizer["RESET"]">
<div>
<h5 text-translate="true">Disable Authenticator</h5>
<p class="mb-0 me-3" text-translate="true">Invalidates the current authenticator configuration. Useful if you believe your authenticator settings were compromised or if you want to disable authenticator.</p>
Why this scored 35/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.