@page "/setup-2fa" @inject IAuthService AuthService @inject NavigationManager Navigation @inject IJSRuntime JSRuntime @inject ILocalizationService Loc @rendermode InteractiveServer @attribute [Microsoft.AspNetCore.Authorization.Authorize] @Loc["page.title.setup2fa"]

@Loc["setup2fa.heading"]

@if (isEnabled) {

@Loc["setup2fa.status.enabled"]

} else if (showSecret) {

@Loc["setup2fa.instruction"]

QR Code
@secret
} else {

@Loc["setup2fa.description"]

} @if (!string.IsNullOrEmpty(errorMessage)) {
@errorMessage
}
@code { private string secret = string.Empty; private string verificationCode = string.Empty; private string errorMessage = string.Empty; private string? qrCodeDataUri; private bool showSecret; private bool isEnabled; private bool isBusy; private string? username; private bool _enableDisabled => isBusy || string.IsNullOrWhiteSpace(verificationCode); protected override async Task OnInitializedAsync() { isEnabled = await AuthService.Is2FAEnabledAsync(); var user = await AuthService.GetCurrentUserAsync(); username = user?.Name; } private async Task HandleKeyDown(KeyboardEventArgs e) { if (e.Key == "Enter") await Enable2FA(); } private async Task StartSetup() { isBusy = true; try { secret = await AuthService.Generate2FASecretAsync(); var uri = AuthService.Get2FAProvisioningUri(secret, username ?? "user"); qrCodeDataUri = await GenerateQRCodeDataUri(uri); showSecret = true; } catch (Exception ex) { errorMessage = $"{Loc["common.error"]} {ex.Message}"; } finally { isBusy = false; } } private async Task Enable2FA() { if (string.IsNullOrWhiteSpace(verificationCode) || verificationCode.Length != 6) { errorMessage = Loc["setup2fa.error.invalid_code"]; return; } if (!TotpHelper.VerifyCode(secret, verificationCode)) { errorMessage = Loc["setup2fa.error.code_invalid"]; return; } isBusy = true; errorMessage = string.Empty; try { var result = await AuthService.Enable2FAAsync(secret); if (result) { isEnabled = true; showSecret = false; } else { errorMessage = Loc["setup2fa.error.enable_failed"]; } } catch (Exception ex) { errorMessage = $"{Loc["common.error"]} {ex.Message}"; } finally { isBusy = false; } } private async Task Disable2FA() { isBusy = true; try { var result = await AuthService.Disable2FAAsync(); if (result) { isEnabled = false; showSecret = false; secret = string.Empty; } } catch (Exception ex) { errorMessage = $"{Loc["common.error"]} {ex.Message}"; } finally { isBusy = false; } } private async Task GenerateQRCodeDataUri(string uri) { try { var encoded = System.Web.HttpUtility.UrlEncode(uri); return $"https://api.qrserver.com/v1/create-qr-code/?size=200x200&data={encoded}"; } catch { return null; } } private async Task CopySecret() { if (!string.IsNullOrEmpty(secret)) await JSRuntime.InvokeVoidAsync("navigator.clipboard.writeText", secret); } private void Cancel() { Navigation.NavigateTo("/"); } }