Repository: dotnetcore/BootstrapBlazor
Pull request #5912: doc(ITotpService): add sample code
Author: login: ArgoZhang
Labels: name: documentation
description: Improvements or additions to documentation
Created: 2025-04-27T08:16:52Z | Merged: 2025-04-27T08:21:33Z

## Link issues
fixes #5911 

<!--[Please fill in the relevant Issue number after the # above, such as #42]-->
<!--[请在上方 # 后面填写相关 Issue 编号，如 #42]-->

## Summary By Copilot
This pull request introduces significant changes to the `BootstrapBlazor` project, focusing on replacing the `BootstrapBlazor.Authenticator` component with a new `ITotpService` implementation. The changes include updates to project references, renaming files and classes, modifying localization files, and improving the TOTP service's API. Below is a summary of the most important changes grouped by theme.

### Removal of `BootstrapBlazor.Authenticator` and Introduction of `ITotpService`:
* Removed the `BootstrapBlazor.Authenticator` project reference from `BootstrapBlazor.sln` and replaced it with `ITotpService` functionality in the `BootstrapBlazor.Server` project. (`[[1]](diffhunk://#diff-870ac4a4b1c5ee4def744573119c9717970bba3b8d2a460723e46a16e6f94d39L81-L82)`, `[[2]](diffhunk://#diff-acda8ffd7b0362074afe236cb631a348f2c8a44568a1f235743982c2a0ad6416R24)`, `[[3]](diffhunk://#diff-acda8ffd7b0362074afe236cb631a348f2c8a44568a1f235743982c2a0ad6416L72-L81)`, `[[4]](diffhunk://#diff-8ec92a1c789bcd9f30e2bf5f32650e11512a8d9818d4bb826d144b69f96a5181L33-R34)`)
* Replaced the `Authenticator` sample with a new `OtpServices` sample, including renaming the Razor and code-behind files, updating the implementation to use the new `ITotpService`, and adding a new demo page. (`[[1]](diffhunk://#diff-1870f0684661390279b8dabb1fc420f521ff8d2e98a9d30dbf973af1dbfa597cL1-L39)`, `[[2]](diffhunk://#diff-436a2abad2c2c0fe81cb6a4a49310b861d8a3656cda22a6e43016827dbb3bf92R1-R56)`, `[[3]](diffhunk://#diff-61a86a9cf933da975b47868eba7ec96cbb748ed2583f4c75789390c9a7f0da07L10-R16)`, `[[4]](diffhunk://#diff-61a86a9cf933da975b47868eba7ec96cbb748ed2583f4c75789390c9a7f0da07L37-R45)`, `[[5]](diffhunk://#diff-0da175523aa74d67c07cc125ac55664960a8e14e9b980fc8394ee1b9fff866f7R1541-R1546)`)

### API Enhancements for TOTP Service:
* Updated the `ITotpService` interface and its implementation to use more descriptive parameter names (`step` → `period`, `totpSize` → `digits`) and aligned the API with standard TOTP terminology. (`[[1]](diffhunk://#diff-ccc7650d5da806a4fcb0148dc7fde082c94c49c7492f681c1ae7b96a26e1a427L12-R12)`, `[[2]](diffhunk://#diff-bb486b36d893ea93119d3c1e13e85f33e2ba5c15ce6f093b18e51cd7ad8b110cL24-R29)`)

### Localization Updates:
* Updated the localization files (`en-US.json` and `zh-CN.json`) to reflect the changes from `Authenticator` to `ITotpService`, including new keys for the `OtpServices` demo. (`[[1]](diffhunk://#diff-790d42ebea731775f0fee88a92b20fadb044e53706fd6d3025dfa095df9b1b41L4923-R4923)`, `[[2]](diffhunk://#diff-790d42ebea731775f0fee88a92b20fadb044e53706fd6d3025dfa095df9b1b41L7106-R7110)`, `[[3]](diffhunk://#diff-746b8cc3c80dd10d0a1bf77b8d6571652e15bcc7c33dcac0954d93b1a728cc7fL4923-R4923)`, `[[4]](diffhunk://#diff-746b8cc3c80dd10d0a1bf77b8d6571652e15bcc7c33dcac0954d93b1a728cc7fL7106-R7110)`)

### Documentation and Versioning:
* Updated the `docs.json` file to replace references to `authenticator` with `otp-service`. (`[src/BootstrapBlazor.Server/docs.jsonL233-R233](diffhunk://#diff-7f22699a321cdff3a7bd4a3f85ae66d0fbe78560628329c39cca784d9d64dfb7L233-R233)`)
* Incremented the version of `BootstrapBlazor` from `9.5.11-beta04` to `9.5.12`. (`[src/BootstrapBlazor/BootstrapBlazor.csprojL4-R4](diffhunk://#diff-07918ce1b66955e76da5cd0ffa38512cce984fa2a09735a60e0db37b45235527L4-R4)`)

These changes streamline the implementation of TOTP functionality, improve code clarity, and enhance the user experience with updated samples and documentation.

## Regression?
- [ ] Yes
- [ ] No

<!--[If yes, specify the version the behavior has regressed from]-->
<!--[是否影响老版本]-->

## Risk
- [ ] High
- [ ] Medium
- [ ] Low

<!--[Justify the selection above]-->

## Verification
- [ ] Manual (required)
- [ ] Automated

## Packaging changes reviewed?
- [ ] Yes
- [ ] No
- [ ] N/A

## ☑️ Self Check before Merge
⚠️ Please check all items below before review. ⚠️
- [ ] Doc is updated/provided or not needed
- [ ] Demo is updated/provided or not needed
- [ ] Merge the latest code from the main branch

## Summary by Sourcery

Introduce `ITotpService` and a corresponding sample page, replacing the previous `Authenticator` component and sample. Rename service API parameters for clarity.

Enhancements:
- Rename `ITotpService.Compute` parameters (`step` to `period`, `totpSize` to `digits`) to align with standard TOTP terminology.
- Replace the `Authenticator` sample page with a new `OtpServices` page demonstrating `ITotpService` usage.
- Update service registration to use `AddBootstrapBlazorTotpService` instead of the previous `AddBootstrapBlazorAuthenticator` method.
- Increment the package version in the project file.
- Update documentation metadata and localization files to reflect the new `OtpServices` sample.

Linked issue #5911: doc(ITotpService): add sample code
### Document describing which component

Add sample code for {Component}

Linked issue comments: user: login: bb-auto[bot]
created_at: 2025-04-27T08:16:33Z
body: @ArgoZhang Thank you for submitting the document which is very important for our project.
author_association: NONE

Diff:
diff --git a/BootstrapBlazor.sln b/BootstrapBlazor.sln
index 84f4e0c6412..c0db3d47fbb 100644
--- a/BootstrapBlazor.sln
+++ b/BootstrapBlazor.sln
@@ -78,8 +78,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{9BAF50BE
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTest.Benchmarks", "tools\Benchmarks\UnitTest.Benchmarks.csproj", "{3E6D8D0E-5A36-4CFD-8612-7D64E3FFE7B1}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BootstrapBlazor.Authenticator", "..\BootstrapBlazor.Extensions\src\components\BootstrapBlazor.Authenticator\BootstrapBlazor.Authenticator.csproj", "{51641ADB-69FA-6DDF-F83F-FEA0C5AFFD88}"
-EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -114,10 +112,6 @@ Global
 		{3E6D8D0E-5A36-4CFD-8612-7D64E3FFE7B1}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{3E6D8D0E-5A36-4CFD-8612-7D64E3FFE7B1}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{3E6D8D0E-5A36-4CFD-8612-7D64E3FFE7B1}.Release|Any CPU.Build.0 = Release|Any CPU
-		{51641ADB-69FA-6DDF-F83F-FEA0C5AFFD88}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{51641ADB-69FA-6DDF-F83F-FEA0C5AFFD88}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{51641ADB-69FA-6DDF-F83F-FEA0C5AFFD88}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{51641ADB-69FA-6DDF-F83F-FEA0C5AFFD88}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -134,7 +128,6 @@ Global
 		{D8AEAFE7-10AF-4A5B-BC67-FE740A2CA1DF} = {7C1D79F1-87BC-42C1-BD5A-CDE4044AC1BD}
 		{C075C6C8-B9CB-4AC0-9BDF-B2002B4AB99C} = {EA765165-0542-41C8-93F2-85787FEDEDFF}
 		{3E6D8D0E-5A36-4CFD-8612-7D64E3FFE7B1} = {9BAF50BE-141D-4429-93A9-942F373D1F68}
-		{51641ADB-69FA-6DDF-F83F-FEA0C5AFFD88} = {A2182155-43ED-44C1-BF6F-1B70EBD2DFFE}
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
 		SolutionGuid = {0DCB0756-34FA-4FD0-AE1D-D3F08B5B3A6B}
diff --git a/src/BootstrapBlazor.Server/BootstrapBlazor.Server.csproj b/src/BootstrapBlazor.Server/BootstrapBlazor.Server.csproj
index 5b3d1e4dfb4..f8f022f4220 100644
--- a/src/BootstrapBlazor.Server/BootstrapBlazor.Server.csproj
+++ b/src/BootstrapBlazor.Server/BootstrapBlazor.Server.csproj
@@ -21,6 +21,7 @@
 
   <ItemGroup>
     <PackageReference Include="BootstrapBlazor.AntDesignIcon" Version="9.0.3" />
+    <PackageReference Include="BootstrapBlazor.Authenticator" Version="9.0.0" />
     <PackageReference Include="BootstrapBlazor.AzureOpenAI" Version="9.0.0" />
     <PackageReference Include="BootstrapBlazor.AzureTranslator" Version="9.0.0" />
     <PackageReference Include="BootstrapBlazor.BaiduSpeech" Version="9.0.0" />
@@ -50,6 +51,7 @@
     <PackageReference Include="BootstrapBlazor.MaterialDesign" Version="9.0.1" />
     <PackageReference Include="BootstrapBlazor.MeiliSearch" Version="9.1.9" />
     <PackageReference Include="BootstrapBlazor.Mermaid" Version="9.0.4" />
+    <PackageReference Include="BootstrapBlazor.Middleware" Version="9.0.0" />
     <PackageReference Include="BootstrapBlazor.MindMap" Version="9.1.6" />
     <PackageReference Include="BootstrapBlazor.MouseFollower" Version="9.0.1" />
     <PackageReference Include="BootstrapBlazor.OctIcon" Version="9.0.4" />
@@ -69,16 +71,11 @@
     <PackageReference Include="BootstrapBlazor.UniverSheet" Version="9.0.3" />
     <PackageReference Include="BootstrapBlazor.VideoPlayer" Version="9.0.3" />
     <PackageReference Include="BootstrapBlazor.WinBox" Version="9.0.7" />
-  </ItemGroup>
-
-  <ItemGroup>
-    <PackageReference Include="BootstrapBlazor.Middleware" Version="9.0.0" />
     <PackageReference Include="Longbow.Logging" Version="9.0.0" />
     <PackageReference Include="Longbow.Tasks" Version="9.0.0" />
   </ItemGroup>
 
   <ItemGroup>
-    <ProjectReference Include="..\..\..\BootstrapBlazor.Extensions\src\components\BootstrapBlazor.Authenticator\BootstrapBlazor.Authenticator.csproj" />
     <ProjectReference Include="..\BootstrapBlazor\BootstrapBlazor.csproj" />
   </ItemGroup>
 
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Authenticators.razor b/src/BootstrapBlazor.Server/Components/Samples/Authenticators.razor
deleted file mode 100644
index 14deaa574a2..00000000000
--- a/src/BootstrapBlazor.Server/Components/Samples/Authenticators.razor
+++ /dev/null
@@ -1,39 +0,0 @@
-﻿@page "/authenticator"
-
-<HeadContent>
-    <style>
-        .qrcode {
-            display: flex;
-            justify-content: center;
-        }
-
-        .progress {
-            max-width: 500px;
-            margin: 0 auto;
-        }
-
-        .opt-progress-label {
-            position: absolute;
-            top: 50%;
-            left: 50%;
-            transform: translate(-50%, -50%);
-            font-size: 0.75rem;
-            color: var(--bs-body-color);
-        }
-    </style>
-</HeadContent>
-
-<h3>@Localizer["Title"]</h3>
-
-<h4>@Localizer["SubTitle"]</h4>
-
-<PackageTips Name="BootstrapBlazor.Authenticator"></PackageTips>
-
-<DemoBlock Title="@Localizer["BaseUsageText"]" Introduction="@Localizer["IntroText1"]" Name="Normal">
-    <QRCode Content="@_content" Width="190" class="mb-3"></QRCode>
-    <OtpInput Value="@_code" IsReadonly="true" class="text-center mb-3"></OtpInput>
-    <div class="position-relative">
-        <BootstrapBlazor.Components.Progress Value="@_progress" IsShowValue="false"></BootstrapBlazor.Components.Progress>
-        <span class="opt-progress-label">@_remain</span>
-    </div>
-</DemoBlock>
diff --git a/src/BootstrapBlazor.Server/Components/Samples/OtpServices.razor b/src/BootstrapBlazor.Server/Components/Samples/OtpServices.razor
new file mode 100644
index 00000000000..06c27bb5285
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Samples/OtpServices.razor
@@ -0,0 +1,56 @@
+﻿@page "/otp-service"
+
+<HeadContent>
+    <style>
+        .qrcode {
+            display: flex;
+            justify-content: center;
+        }
+
+        .progress {
+            max-width: 500px;
+            margin: 0 auto;
+        }
+
+        .opt-progress-label {
+            position: absolute;
+            top: 50%;
+            left: 50%;
+            transform: translate(-50%, -50%);
+            font-size: 0.75rem;
+            color: var(--bs-body-color);
+        }
+    </style>
+</HeadContent>
+
+<h3>@Localizer["Title"]</h3>
+
+<h4>@Localizer["SubTitle"]</h4>
+
+<PackageTips Name="BootstrapBlazor.Authenticator"></PackageTips>
+
+<DemoBlock Title="@Localizer["BaseUsageTitle"]" Introduction="@Localizer["BaseUsageIntro"]" Name="Normal">
+    <QRCode Content="@_content" Width="190" class="mb-3"></QRCode>
+    <OtpInput Value="@_code" IsReadonly="true" class="text-center mb-3"></OtpInput>
+    <div class="position-relative">
+        <BootstrapBlazor.Components.Progress Value="@_progress" IsShowValue="false"></BootstrapBlazor.Components.Progress>
+        <span class="opt-progress-label">@_remain</span>
+    </div>
+</DemoBlock>
+
+<p class="code-label mt-3">1. 服务注入</p>
+
+<Pre>[Inject]
+[NotNull]
+private ITotpService? TotpService { get; set; }</Pre>
+
+<p class="code-label">2. 生成二维码</p>
+<p>调用 <code>TotpService</code> 实例方法 <code>GenerateOtpUri</code> 得到二维码内容，配合二维码组件 <code>QRCode</code> 显示二维码</p>
+
+<p class="code-label">3. 使用 <code>Microsoft Authenticator</code> <code>Google Authenticator</code> 等支持 <b>TOTP</b> 协议的软件，扫描二维码</p>
+
+<p class="code-label">4. 验证逻辑</p>
+
+<p>网页内使用 <code>OtpInput</code> 让用户填写手机 <code>App</code> 终端的密码，后台通过调用 <code>TotpService</code> 实例方法 <code>Compute</code> 得到当前时间窗口内的密码，与客户录入的比对，如果一致则密码正确</p>
+
+<div>通过使用本服务可以很方便的构建 <code>2FA</code> 应用</div>
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Authenticators.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/OtpServices.razor.cs
similarity index 74%
rename from src/BootstrapBlazor.Server/Components/Samples/Authenticators.razor.cs
rename to src/BootstrapBlazor.Server/Components/Samples/OtpServices.razor.cs
index bb991958b09..607841285ce 100644
--- a/src/BootstrapBlazor.Server/Components/Samples/Authenticators.razor.cs
+++ b/src/BootstrapBlazor.Server/Components/Samples/OtpServices.razor.cs
@@ -7,13 +7,13 @@
 namespace BootstrapBlazor.Server.Components.Samples;
 
 /// <summary>
-/// Authenticators sample
+/// OtpServices sample
 /// </summary>
-public partial class Authenticators
+public partial class OtpServices
 {
     [Inject]
     [NotNull]
-    private IStringLocalizer<Anchors>? Localizer { get; set; }
+    private IStringLocalizer<OtpServices>? Localizer { get; set; }
 
     [Inject]
     [NotNull]
@@ -34,7 +34,15 @@ protected override void OnInitialized()
     {
         base.OnInitialized();
 
-        _content = TotpService.GenerateOtpUri();
+        _content = TotpService.GenerateOtpUri(new OtpOptions()
+        {
+            AccountName = "BootstrapBlazor",
+            IssuerName = "BootstrapBlazor",
+            UserName = "Simulator",
+            SecretKey = "OMM2LVLFX6QJHMYI",
+            Algorithm = OtpHashMode.Sha1,
+            Type = OtpType.Totp
+        });
         _code = TotpService.Compute("OMM2LVLFX6QJHMYI");
     }
 
diff --git a/src/BootstrapBlazor.Server/Extensions/MenusLocalizerExtensions.cs b/src/BootstrapBlazor.Server/Extensions/MenusLocalizerExtensions.cs
index b05c4487fc5..4f7c676f2bd 100644
--- a/src/BootstrapBlazor.Server/Extensions/MenusLocalizerExtensions.cs
+++ b/src/BootstrapBlazor.Server/Extensions/MenusLocalizerExtensions.cs
@@ -1538,6 +1538,12 @@ void AddServices(DemoMenuItem item)
                     Url = "theme-provider"
                 },
                 new()
+                {
+                    IsNew = true,
+                    Text = Localizer["TotpService"],
+                    Url = "otp-service"
+                },
+                new()
                 {
                     Text = Localizer["Title"],
                     Url = "title"
diff --git a/src/BootstrapBlazor.Server/Extensions/ServiceCollectionSharedExtensions.cs b/src/BootstrapBlazor.Server/Extensions/ServiceCollectionSharedExtensions.cs
index 742426a667a..5022990d36d 100644
--- a/src/BootstrapBlazor.Server/Extensions/ServiceCollectionSharedExtensions.cs
+++ b/src/BootstrapBlazor.Server/Extensions/ServiceCollectionSharedExtensions.cs
@@ -30,8 +30,8 @@ public static IServiceCollection AddBootstrapBlazorServices(this IServiceCollect
         services.AddSingleton<MenuService>();
         services.AddScoped<FanControllerDataService>();
 
-        // 增加 Authenticator 服务
-        services.AddBootstrapBlazorAuthenticator();
+        // 增加 ITotpService 服务
+        services.AddBootstrapBlazorTotpService();
 
         // 增加示例网站配置
         services.AddOptionsMonitor<WebsiteOptions>();
diff --git a/src/BootstrapBlazor.Server/Locales/en-US.json b/src/BootstrapBlazor.Server/Locales/en-US.json
index bcaed03e2f3..7169ae2f7f4 100644
--- a/src/BootstrapBlazor.Server/Locales/en-US.json
+++ b/src/BootstrapBlazor.Server/Locales/en-US.json
@@ -4920,7 +4920,7 @@
     "UniverSheet": "UniverSheet",
     "ShieldBadge": "ShieldBadge",
     "OtpInput": "OtpInput",
-    "Authenticator": "Authenticator"
+    "TotpService": "ITotpService"
   },
   "BootstrapBlazor.Server.Components.Samples.Table.TablesHeader": {
     "TablesHeaderTitle": "Header grouping function",
@@ -7103,8 +7103,10 @@
     "OtpInputsValidateFormTitle": "ValidateForm",
     "OtpInputsValidateFormIntro": "When the password is not provided, click the Submit button, the password box will be displayed in red and it will be prompted that it cannot be empty."
   },
-  "BootstrapBlazor.Server.Components.Samples.Authenticators": {
-    "Title": "Authenticator",
-    "SubTitle": "An implementation TOTP RFC 6238 and HOTP RFC 4226 Authenticator service."
+  "BootstrapBlazor.Server.Components.Samples.OtpServices": {
+    "Title": "ITotpService",
+    "SubTitle": "An implementation TOTP RFC 6238 and HOTP RFC 4226 Authenticator service.",
+    "BaseUsageTitle": "Basic usage",
+    "BaseUsageIntro": "By calling the <code>Compute</code> method of the <code>ITotpService</code> service instance, you can get the password in the current time window. By calling the <code>Instance.GetRemainingSeconds</code> method, you can display the remaining validity time of the current password. In this example, the progress bar is used for dynamic display."
   }
 }
diff --git a/src/BootstrapBlazor.Server/Locales/zh-CN.json b/src/BootstrapBlazor.Server/Locales/zh-CN.json
index 61d6eab5bff..9f7cb81d290 100644
--- a/src/BootstrapBlazor.Server/Locales/zh-CN.json
+++ b/src/BootstrapBlazor.Server/Locales/zh-CN.json
@@ -4920,7 +4920,7 @@
     "UniverSheet": "表格组件 UniverSheet",
     "ShieldBadge": "徽章组件 ShieldBadge",
     "OtpInput": "验证码输入框 OtpInput",
-    "Authenticator": "密码验证服务 Authenticator"
+    "TotpService": "时间密码验证服务 ITotpService"
   },
   "BootstrapBlazor.Server.Components.Samples.Table.TablesHeader": {
     "TablesHeaderTitle": "表头分组功能",
@@ -7103,8 +7103,10 @@
     "OtpInputsValidateFormTitle": "表单内使用",
     "OtpInputsValidateFormIntro": "密码未提供值时，点击提交按钮，密码框显示为红色，并且提示不可为空"
   },
-  "BootstrapBlazor.Server.Components.Samples.Authenticators": {
-    "Title": "Authenticator 密码验证服务",
-    "SubTitle": "实现 TOTP RFC 6238 和 HOTP RFC 4226 认证器服务"
+  "BootstrapBlazor.Server.Components.Samples.OtpServices": {
+    "Title": "ITotpService 时间密码验证服务",
+    "SubTitle": "实现 TOTP RFC 6238 和 HOTP RFC 4226 认证器服务",
+    "BaseUsageTitle": "基本用法",
+    "BaseUsageIntro": "通过调用 <code>ITotpService</code> 服务实例方法 <code>Compute</code> 得到当前时间窗口内密码, 通过调用 <code>Instance.GetRemainingSeconds</code> 方法可以显示当前密码剩余有效时间，本例中通过进度条进行动态显示"
   }
 }
diff --git a/src/BootstrapBlazor.Server/docs.json b/src/BootstrapBlazor.Server/docs.json
index e41cd5a16d0..c86e547fe12 100644
--- a/src/BootstrapBlazor.Server/docs.json
+++ b/src/BootstrapBlazor.Server/docs.json
@@ -230,7 +230,7 @@
     "univer-sheet": "UniverSheets",
     "shield-badge": "ShieldBadges",
     "opt-input": "OtpInputs",
-    "authenticator": "Authenticators"
+    "otp-service": "OtpServices"
   },
   "video": {
     "table": "BV1ap4y1x7Qn?p=1",
diff --git a/src/BootstrapBlazor/BootstrapBlazor.csproj b/src/BootstrapBlazor/BootstrapBlazor.csproj
index 496df7c93e2..f95f4198540 100644
--- a/src/BootstrapBlazor/BootstrapBlazor.csproj
+++ b/src/BootstrapBlazor/BootstrapBlazor.csproj
@@ -1,7 +1,7 @@
 ﻿<Project Sdk="Microsoft.NET.Sdk.Razor">
 
   <PropertyGroup>
-    <Version>9.5.11-beta04</Version>
+    <Version>9.5.12</Version>
   </PropertyGroup>
 
   <ItemGroup>
diff --git a/src/BootstrapBlazor/Services/DefaultTotpService.cs b/src/BootstrapBlazor/Services/DefaultTotpService.cs
index 4596c65ebff..b59bdd07bb1 100644
--- a/src/BootstrapBlazor/Services/DefaultTotpService.cs
+++ b/src/BootstrapBlazor/Services/DefaultTotpService.cs
@@ -9,7 +9,7 @@ class DefaultTotpService : ITotpService
 {
     public TotpInstanceBase Instance { get; } = new DefaultTotpInstance();
 
-    public string Compute(string secretKey, int step = 6, OtpHashMode mode = OtpHashMode.Sha1, int totpSize = 6, DateTime? timestamp = null) => "123456";
+    public string Compute(string secretKey, int period = 30, OtpHashMode mode = OtpHashMode.Sha1, int digits = 6, DateTime? timestamp = null) => "123456";
 
     public string GenerateOtpUri(OtpOptions? options = null) => "otpauth://totp/BootstrapBlazor?secret=OMM2LVLFX6QJHMYI&issuer=Simulator";
 
diff --git a/src/BootstrapBlazor/Services/ITotpService.cs b/src/BootstrapBlazor/Services/ITotpService.cs
index 7a3bf1b6e17..c0efbb0ef07 100644
--- a/src/BootstrapBlazor/Services/ITotpService.cs
+++ b/src/BootstrapBlazor/Services/ITotpService.cs
@@ -21,12 +21,12 @@ public interface ITotpService
     /// Computes the Time-based One-Time Password (TOTP) for the given secret key and timestamp.
     /// </summary>
     /// <param name="secretKey"></param>
-    /// <param name="step"></param>
+    /// <param name="period"></param>
     /// <param name="mode"></param>
-    /// <param name="totpSize"></param>
+    /// <param name="digits"></param>
     /// <param name="timestamp"></param>
     /// <returns></returns>
-    string Compute(string secretKey, int step = 6, OtpHashMode mode = OtpHashMode.Sha1, int totpSize = 6, DateTime? timestamp = null);
+    string Compute(string secretKey, int period = 30, OtpHashMode mode = OtpHashMode.Sha1, int digits = 6, DateTime? timestamp = null);
 
     /// <summary>
     /// Computes the remaining seconds until the next TOTP expiration for the given secret key and timestamp.


Reviews:
user: login: copilot-pull-request-reviewer[bot]
body: ## Pull Request Overview

This PR replaces the BootstrapBlazor.Authenticator component with a new ITotpService implementation and updates the related samples, localization, and documentation accordingly.
- Renamed and updated parameters in the ITotpService API (step → period, totpSize → digits).
- Introduced an OtpServices sample and removed the old Authenticators sample.
- Updated service registration, localization files, and docs to reflect the changes.

### Reviewed Changes

Copilot reviewed 7 out of 13 changed files in this pull request and generated 1 comment.

<details>
<summary>Show a summary per file</summary>

| File | Description |
| ---- | ----------- |
| src/BootstrapBlazor/Services/ITotpService.cs | Updated parameter names and documentation in the TOTP service interface |
| src/BootstrapBlazor/Services/DefaultTotpService.cs | Updated parameter names and defaults in the TOTP service implementation |
| src/BootstrapBlazor.Server/Extensions/ServiceCollectionSharedExtensions.cs | Updated service registration for the new ITotpService |
| src/BootstrapBlazor.Server/Extensions/MenusLocalizerExtensions.cs | Added a new menu entry for TotpService |
| src/BootstrapBlazor.Server/Components/Samples/OtpServices.razor.cs | Renamed sample class and updated service usage with new OtpOptions |
| src/BootstrapBlazor.Server/Components/Samples/OtpServices.razor | Created a new sample page for ITotpService |
| src/BootstrapBlazor.Server/Components/Samples/Authenticators.razor | Removed the old Authenticator sample |
</details>


<details>
<summary>Files not reviewed (6)</summary>

* **BootstrapBlazor.sln**: Language not supported
* **src/BootstrapBlazor.Server/BootstrapBlazor.Server.csproj**: Language not supported
* **src/BootstrapBlazor.Server/Locales/en-US.json**: Language not supported
* **src/BootstrapBlazor.Server/Locales/zh-CN.json**: Language not supported
* **src/BootstrapBlazor.Server/docs.json**: Language not supported
* **src/BootstrapBlazor/BootstrapBlazor.csproj**: Language not supported
</details>

<details>
<summary>Comments suppressed due to low confidence (2)</summary>

**src/BootstrapBlazor/Services/ITotpService.cs:29**
* The default value for 'period' is set to 6, which is non-standard given that TOTP periods are typically 30 seconds. Please verify and update the default if needed.
```
string Compute(string secretKey, int period = 6, OtpHashMode mode = OtpHashMode.Sha1, int digits = 6, DateTime? timestamp = null);
```
**src/BootstrapBlazor.Server/Components/Samples/OtpServices.razor:30**
* The PackageTips component still references 'BootstrapBlazor.Authenticator'; update it to reference 'BootstrapBlazor.TotpService' to maintain consistency with the new implementation.
```
<PackageTips Name="BootstrapBlazor.Authenticator"></PackageTips>
```
</details>


state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-27T08:17:43Z
user: login: sourcery-ai[bot]
body: Hey @ArgoZhang - I've reviewed your changes - here's some feedback:

**Overall Comments**:
- Consider updating the PR title and description to better reflect the full scope, which includes replacing the `Authenticator` service with `ITotpService` rather than just adding sample code.

<details>
<summary>Here's what I looked at during the review</summary>

- 🟡 **General issues**: 2 issues found
- 🟢 **Security**: all looks good
- 🟢 **Testing**: all looks good
- 🟢 **Complexity**: all looks good
- 🟢 **Documentation**: all looks good
</details>

***

<details>
<summary>Sourcery is free for open source - if you like our reviews please consider sharing them ✨</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20got%20an%20instant%20code%20review%20from%20%40SourceryAI%2C%20and%20it%20was%20brilliant%21%20It%27s%20free%20for%20open%20source%20and%20has%20a%20free%20trial%20for%20private%20code.%20Check%20it%20out%20https%3A//sourcery.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20got%20an%20instant%20code%20review%20from%20%40SourceryAI%2C%20and%20it%20was%20brilliant%21%20It%27s%20free%20for%20open%20source%20and%20has%20a%20free%20trial%20for%20private%20code.%20Check%20it%20out%20https%3A//sourcery.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https://sourcery.ai)
- [Facebook](https://www.facebook.com/sharer/sharer.php?u=https://sourcery.ai)

</details>

<sub>
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
</sub>
state: DISMISSED
author_association: CONTRIBUTOR
submitted_at: 2025-04-27T08:18:04Z

Review comments:
diff_hunk: @@ -9,7 +9,7 @@ class DefaultTotpService : ITotpService
 {
     public TotpInstanceBase Instance { get; } = new DefaultTotpInstance();
 
-    public string Compute(string secretKey, int step = 6, OtpHashMode mode = OtpHashMode.Sha1, int totpSize = 6, DateTime? timestamp = null) => "123456";
+    public string Compute(string secretKey, int period = 6, OtpHashMode mode = OtpHashMode.Sha1, int digits = 6, DateTime? timestamp = null) => "123456";
 
path: src/BootstrapBlazor/Services/DefaultTotpService.cs
user: login: Copilot
body: The Compute method uses a default 'period' of 6 seconds, which might conflict with standard TOTP time windows of 30 seconds. Consider reviewing and correcting this default value.
```suggestion
    public string Compute(string secretKey, int period = 30, OtpHashMode mode = OtpHashMode.Sha1, int digits = 6, DateTime? timestamp = null) => "123456";
```
created_at: 2025-04-27T08:17:42Z
author_association: CONTRIBUTOR
diff_hunk: @@ -9,7 +9,7 @@ class DefaultTotpService : ITotpService
 {
     public TotpInstanceBase Instance { get; } = new DefaultTotpInstance();
 
-    public string Compute(string secretKey, int step = 6, OtpHashMode mode = OtpHashMode.Sha1, int totpSize = 6, DateTime? timestamp = null) => "123456";
+    public string Compute(string secretKey, int period = 6, OtpHashMode mode = OtpHashMode.Sha1, int digits = 6, DateTime? timestamp = null) => "123456";
path: src/BootstrapBlazor/Services/DefaultTotpService.cs
user: login: sourcery-ai[bot]
body: **issue (bug_risk):** Mismatch in default 'period' parameter value compared to the interface.

The ITotpService interface sets a default period of 30 seconds, but the implementation here uses 6 seconds. Aligning these defaults would help avoid unexpected behaviors.
created_at: 2025-04-27T08:18:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -9,7 +9,7 @@ class DefaultTotpService : ITotpService
 {
     public TotpInstanceBase Instance { get; } = new DefaultTotpInstance();
 
-    public string Compute(string secretKey, int step = 6, OtpHashMode mode = OtpHashMode.Sha1, int totpSize = 6, DateTime? timestamp = null) => "123456";
+    public string Compute(string secretKey, int period = 6, OtpHashMode mode = OtpHashMode.Sha1, int digits = 6, DateTime? timestamp = null) => "123456";
 
     public string GenerateOtpUri(OtpOptions? options = null) => "otpauth://totp/BootstrapBlazor?secret=OMM2LVLFX6QJHMYI&issuer=Simulator";
path: src/BootstrapBlazor/Services/DefaultTotpService.cs
user: login: sourcery-ai[bot]
body: **suggestion:** Provided OtpOptions parameter is not used in the URI generation.

If the intent is to allow customization through the OtpOptions, consider integrating the options into the generated URI. Otherwise, documenting that the parameter is currently ignored would improve clarity.

Suggested implementation:

```csharp
    public string GenerateOtpUri(OtpOptions? options = null)
    {
        // If options is null, set default values
        options ??= new OtpOptions
        {
            Label = "BootstrapBlazor",
            Secret = "OMM2LVLFX6QJHMYI",
            Issuer = "Simulator",
            // Providing default values for additional parameters
            Period = 30,
            Digits = 6,
            Mode = OtpHashMode.Sha1
        };

        var uri = $"otpauth://totp/{Uri.EscapeDataString(options.Label)}?secret={options.Secret}&issuer={Uri.EscapeDataString(options.Issuer)}";

        // Append the period if set
        if (options.Period > 0)
        {
            uri += $"&period={options.Period}";
        }

        // Append the digits if set
        if (options.Digits > 0)
        {
            uri += $"&digits={options.Digits}";
        }

        // Append the algorithm (hash mode)
        uri += $"&algorithm={options.Mode.ToString().ToUpper()}";

        return uri;
    }

```

Review the OtpOptions class to ensure that it contains the properties: Label, Secret, Issuer, Period, Digits, and Mode. Adjust the default values as needed to adhere to your expected behavior in your codebase.
created_at: 2025-04-27T08:18:04Z
author_association: CONTRIBUTOR

PR comments:
user: login: sourcery-ai[bot]
created_at: 2025-04-27T08:16:56Z
body: <!-- Generated by sourcery-ai[bot]: start review_guide -->

## Reviewer's Guide by Sourcery

This pull request replaces the existing `BootstrapBlazor.Authenticator` component/service with a new `ITotpService` implementation. The changes involve removing the old component, introducing the new service interface and default implementation, updating sample code, renaming files, modifying localization strings, updating documentation and project references, and refining the API parameter names.

_No diagrams generated as the changes look simple and do not need a visual representation._

### File-Level Changes

| Change | Details | Files |
| ------ | ------- | ----- |
| Replaced the BootstrapBlazor.Authenticator component/service with a new ITotpService implementation. | <ul><li>Removed reference to old Authenticator project.</li><li>Added registration for the new ITotpService.</li><li>Defined the ITotpService interface.</li><li>Provided a default implementation for ITotpService.</li></ul> | `BootstrapBlazor.sln`<br/>`src/BootstrapBlazor.Server/BootstrapBlazor.Server.csproj`<br/>`src/BootstrapBlazor.Server/Extensions/ServiceCollectionSharedExtensions.cs`<br/>`src/BootstrapBlazor/Services/ITotpService.cs`<br/>`src/BootstrapBlazor/Services/DefaultTotpService.cs` |
| Replaced the existing Authenticator sample page with a new OtpServices sample page. | <ul><li>Renamed sample code-behind file.</li><li>Renamed sample Razor file.</li><li>Implemented the sample using the new ITotpService.</li><li>Added new sample page to the menu.</li></ul> | `src/BootstrapBlazor.Server/Components/Samples/Authenticators.razor.cs`<br/>`src/BootstrapBlazor.Server/Components/Samples/OtpServices.razor.cs`<br/>`src/BootstrapBlazor.Server/Components/Samples/Authenticators.razor`<br/>`src/BootstrapBlazor.Server/Components/Samples/OtpServices.razor`<br/>`src/BootstrapBlazor.Server/Extensions/MenusLocalizerExtensions.cs` |
| Refined the ITotpService API parameter names for clarity. | <ul><li>Renamed 'step' parameter to 'period'.</li><li>Renamed 'totpSize' parameter to 'digits'.</li></ul> | `src/BootstrapBlazor/Services/ITotpService.cs`<br/>`src/BootstrapBlazor/Services/DefaultTotpService.cs` |
| Updated localization files and documentation to reflect the changes. | <ul><li>Added new localization keys for the OtpServices sample.</li><li>Updated existing localization strings.</li><li>Updated documentation references.</li></ul> | `src/BootstrapBlazor.Server/Locales/en-US.json`<br/>`src/BootstrapBlazor.Server/Locales/zh-CN.json`<br/>`src/BootstrapBlazor.Server/docs.json` |
| Incremented the project version. | <ul><li>Updated the version number in the project file.</li></ul> | `src/BootstrapBlazor/BootstrapBlazor.csproj` |

### Assessment against linked issues

| Issue | Objective | Addressed | Explanation |
| ------ | ------- | ----- | ----- |
| #5911 | Add sample code for the ITotpService component. | ✅ |  |

### Possibly linked issues

- **#5911**: The PR replaces Authenticator with ITotpService and adds samples/docs, directly addressing the issue.
- **#5911**: PR replaces old Authenticator sample with new ITotpService sample code requested by issue.

---

<details>
<summary>Tips and commands</summary>

#### Interacting with Sourcery

- **Trigger a new review:** Comment `@sourcery-ai review` on the pull request.
- **Continue discussions:** Reply directly to Sourcery's review comments.
- **Generate a GitHub issue from a review comment:** Ask Sourcery to create an
  issue from a review comment by replying to it. You can also reply to a
  review comment with `@sourcery-ai issue` to create an issue from it.
- **Generate a pull request title:** Write `@sourcery-ai` anywhere in the pull
  request title to generate a title at any time. You can also comment
  `@sourcery-ai title` on the pull request to (re-)generate the title at any time.
- **Generate a pull request summary:** Write `@sourcery-ai summary` anywhere in
  the pull request body to generate a PR summary at any time exactly where you
  want it. You can also comment `@sourcery-ai summary` on the pull request to
  (re-)generate the summary at any time.
- **Generate reviewer's guide:** Comment `@sourcery-ai guide` on the pull
  request to (re-)generate the reviewer's guide at any time.
- **Resolve all Sourcery comments:** Comment `@sourcery-ai resolve` on the
  pull request to resolve all Sourcery comments. Useful if you've already
  addressed all the comments and don't want to see them anymore.
- **Dismiss all Sourcery reviews:** Comment `@sourcery-ai dismiss` on the pull
  request to dismiss all existing Sourcery reviews. Especially useful if you
  want to start fresh with a new review - don't forget to comment
  `@sourcery-ai review` to trigger a new review!

#### Customizing Your Experience

Access your [dashboard](https://app.sourcery.ai) to:
- Enable or disable review features such as the Sourcery-generated pull request
  summary, the reviewer's guide, and others.
- Change the review language.
- Add, remove or edit custom review instructions.
- Adjust other review settings.

#### Getting Help

- [Contact our support team](mailto:support@sourcery.ai) for questions or feedback.
- Visit our [documentation](https://docs.sourcery.ai) for detailed guides and information.
- Keep in touch with the Sourcery team by following us on [X/Twitter](https://x.com/SourceryAI), [LinkedIn](https://www.linkedin.com/company/sourcery-ai/) or [GitHub](https://github.com/sourcery-ai).

</details>

<!-- Generated by sourcery-ai[bot]: end review_guide -->
author_association: CONTRIBUTOR
user: login: codecov[bot]
created_at: 2025-04-27T08:19:12Z
body: ## [Codecov](https://app.codecov.io/gh/dotnetcore/BootstrapBlazor/pull/5912?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dotnetcore) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 100.00%. Comparing base [(`a5803ed`)](https://app.codecov.io/gh/dotnetcore/BootstrapBlazor/commit/a5803ed8de4a5fe0507486a9034cbbbc332fb55b?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dotnetcore) to head [(`d44453f`)](https://app.codecov.io/gh/dotnetcore/BootstrapBlazor/commit/d44453fa9eeac04a10d105b4332f0b9f422ef059?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dotnetcore).
> Report is 1 commits behind head on main.

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff            @@
##              main     #5912   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files          665       665           
  Lines        30485     30485           
  Branches      4345      4345           
=========================================
  Hits         30485     30485           
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/dotnetcore/BootstrapBlazor/pull/5912?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dotnetcore).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dotnetcore).

<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
</details>
author_association: NONE