{"id":165,"date":"2025-08-05T17:24:35","date_gmt":"2025-08-05T21:24:35","guid":{"rendered":"http:\/\/wordpress.home.internal\/?p=165"},"modified":"2025-08-07T20:39:49","modified_gmt":"2025-08-07T20:39:49","slug":"a-simple-secured-blazor-application","status":"publish","type":"post","link":"https:\/\/lcigaming.ca\/articles\/a-simple-secured-blazor-application\/","title":{"rendered":"A Simple Secured Blazor Application"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">Introduction<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">My <a href=\"https:\/\/lcigaming.ca\/articles\/supporting-multiple-blazor-apps-with-linux-and-apache\/\" title=\"\">previous post<\/a> showed how one might run multiple Blazor applications on Linux with Apache, and made a reference to an application I use to deploy Blazor apps to our local Linux server. A full review of that app would be too large for a single post, although I can show some aspects.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Although the Linux server I use is physically located in the same room as my development machine, I thought to explore Blazor security when creating my deployment app.  This post shows the results of that endeavour.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The standard creation wizard for Blazor Web Apps available in Visual Studio contains an option for setting the <em>Authentication type<\/em>.  If this is set to &#8220;Individual accounts&#8221;, username-password-based authentication is added to your app using the <a href=\"https:\/\/learn.microsoft.com\/en-us\/aspnet\/core\/security\/authentication\/identity?view=aspnetcore-9.0&amp;tabs=visual-studio\">ASP.NET Core Identity<\/a> framework. While the resulting app is fully functional, it is also quite complex, imposing a structure on application navigation and needing a server database for the usernames and roles.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I desired a much simpler approach for my app. I already had the ability to use a Linux command line to deploy my apps on the server. Once I had logged in to the server, Linux used my user settings to control access to the Apache configuration area and the use of commands such as <em>systemctl<\/em>. If my deployment app could leverage the same controls I would not need special database that I would need to maintain just for that purpose.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I had originally thought to modify the <em>Authentication type<\/em> &#8220;Individual accounts&#8221; app, overriding the necessary components to replace the username database with a &#8220;query&#8221; against the Linux password file. This turned out to be much harder than creating the security mechanism from scratch. I did make use of some of that generated code in my simplified app.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The &#8220;Individual accounts&#8221; app provides several features that I did not need:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Database for usernames and roles<\/li>\n\n\n\n<li>Maintenance screens for that database<\/li>\n\n\n\n<li>Registration mechanism for new accounts<\/li>\n\n\n\n<li>Support for external login providers<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Perhaps the feature that brings the most complexity is the least obvious &#8211; the fact that the generated app supports the persistence of the authentication state across page loads.  This will be explained a bit further on.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Environment<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The environment is the same as with the previous post:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Ubuntu 22.04.1 (LTS)<\/li>\n\n\n\n<li>Apache 2.4.52 (Ubuntu)<\/li>\n\n\n\n<li>dotnet 9.0<\/li>\n\n\n\n<li>Windows 11, Visual Studio for development<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Source Code<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The source code for this post is available on <a href=\"https:\/\/github.com\/BarryALay\/blog0807-source.git\" title=\"\">GitHub<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The Demonstration App<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A concrete example should help with understanding the key concepts.  Perform the following:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Create a new Blazor Web App.  I called mine <em>BlazorSecurityDemo<\/em>.<\/li>\n\n\n\n<li>Select\n<ul class=\"wp-block-list\">\n<li>Authentication type &#8211; None<\/li>\n\n\n\n<li>Interactive render mode &#8211; Server<\/li>\n\n\n\n<li>Interactivity location &#8211; Global<\/li>\n\n\n\n<li>Include sample pages<\/li>\n\n\n\n<li>I chose <em>Do not include top-level statements<\/em>. This is a personal preference and shouldn&#8217;t impact the result.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1012\" height=\"671\" src=\"https:\/\/lcigaming.ca\/articles\/wp-content\/uploads\/2025\/08\/Screenshot-2025-07-20-150457.png\" alt=\"\" class=\"wp-image-104\" srcset=\"https:\/\/lcigaming.ca\/articles\/wp-content\/uploads\/2025\/08\/Screenshot-2025-07-20-150457.png 1012w, https:\/\/lcigaming.ca\/articles\/wp-content\/uploads\/2025\/08\/Screenshot-2025-07-20-150457-300x199.png 300w, https:\/\/lcigaming.ca\/articles\/wp-content\/uploads\/2025\/08\/Screenshot-2025-07-20-150457-768x509.png 768w, https:\/\/lcigaming.ca\/articles\/wp-content\/uploads\/2025\/08\/Screenshot-2025-07-20-150457-360x240.png 360w\" sizes=\"auto, (max-width: 1012px) 100vw, 1012px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The resulting app includes three pages we will not need, but does include some handy infrastructure such as style sheets and the navigation bar.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Apply the same base URL fix as in the previous post.  This gives us more flexibility in deploying the app later.\n<ul class=\"wp-block-list\">\n<li>Remove the <em>base <\/em>directive in <em>Components\/App.razor<\/em>.<\/li>\n\n\n\n<li>Add <em>@page &#8220;\/home&#8221;<\/em> to <em>Components\/Pages\/Home.razor<\/em>.<\/li>\n\n\n\n<li>Modify the first <em>NavLink <\/em>element in <em>Components\/Layout\/NavMenu.razor<\/em> to use <em>href=&#8221;home&#8221;<\/em>.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>In <em>Components\/Layout\/NavMenu.razor<\/em>, remove the <em>NavLink<\/em> elements that have <em>href=&#8221;counter&#8221;<\/em> and <em>href=&#8221;weather&#8221;<\/em>.\n<ul class=\"wp-block-list\">\n<li><em>Counter.razor<\/em> and <em>Weather.razor<\/em> may be deleted from <em>Components\/Pages<\/em>.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Authentication and Authorization<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">In a Blazor app <em>Authentication <\/em>refers to the process of verifying a user&#8217;s identity, whereas <em>Authorization <\/em>refers to the process of controlling access to assets and functionality within the app.  Our demo app will need some modifications in order to provide these processes.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In Program.cs, at the base of the project, register the authentication services:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-highlight-color:rgba(16, 41, 67, 0.2);line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">C#<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>...    \nvar builder = WebApplication.CreateBuilder(args);\n\n\/\/ Add services to the container.\nbuilder.Services.AddRazorComponents().AddInteractiveServerComponents();\n\nbuilder.Services.AddAuthentication();\nbuilder.Services.AddCascadingAuthenticationState();\n\nvar app = builder.Build();\n...\n<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D73A49\">..<\/span><span style=\"color: #24292E\">.    <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">builder<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> WebApplication.<\/span><span style=\"color: #6F42C1\">CreateBuilder<\/span><span style=\"color: #24292E\">(args);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6A737D\">\/\/ Add services to the container.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">builder.Services.<\/span><span style=\"color: #6F42C1\">AddRazorComponents<\/span><span style=\"color: #24292E\">().<\/span><span style=\"color: #6F42C1\">AddInteractiveServerComponents<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">builder.Services.<\/span><span style=\"color: #6F42C1\">AddAuthentication<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">builder.Services.<\/span><span style=\"color: #6F42C1\">AddCascadingAuthenticationState<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">app<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> builder.<\/span><span style=\"color: #6F42C1\">Build<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">..<\/span><span style=\"color: #24292E\">.<\/span><\/span>\n<span class=\"line\"><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">This introduces an <em>AuthenticationState<\/em> to your app which you can use to hide or show items and to control what functionality is available. The <em>AuthenticationState <\/em>holds the active <em>ClaimsPrincipal<\/em>, which provides the <em>ClaimsIdentity<\/em>&#8216;s that have been established for the user of the app. A user will probably have a primary identity from a login to a server. There may also be secondary identities such as those associated with security keys, for example. Each <em>ClaimsIdentity <\/em>will have a list of <em>Claim<\/em>s, or facts associated with that identity. In our case, we will create a <em>ClaimsIdentity <\/em>from the validated Linux user account. The user name and groups related to that account will be captured as <em>Claim<\/em>s.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We will need to add some logic to make this happen.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Create folder <em>Authentication <\/em>at the root of the project.<\/li>\n\n\n\n<li>Create <em>UserAuthenticationStateProvider.cs <\/em>within it:<\/li>\n<\/ul>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-width:calc(2 * 0.6 * .875rem);--cbp-line-highlight-color:rgba(16, 41, 67, 0.2);line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">C#<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>using Microsoft.AspNetCore.Components.Authorization;\nusing System.Security.Claims;\n\nnamespace BlazorSecurityDemo.Authentication\n{\n    public class UserAuthenticationStateProvider : AuthenticationStateProvider\n    {\n        private readonly AuthenticationState authenticationState = \n            new(new ClaimsPrincipal());\n\n        public override Task&lt;AuthenticationState> GetAuthenticationStateAsync()\n        {\n            return Task.FromResult(authenticationState);\n        }\n\n        public async Task&lt;bool> AuthenticateUserPasswordAsync(string username, string password)\n        {\n            \/\/ verify username and password\n\n            IList&lt;Claim> claims = &#91;new Claim(ClaimTypes.Name, username)&#93;;\n\n            var identity = new ClaimsIdentity(claims, \"AuthenticateUser\");\n            var user = new ClaimsPrincipal(identity);\n\n            NotifyAuthenticationStateChanged(\n                Task.FromResult(new AuthenticationState(user)));\n\n            return true;\n        }\n\n        public void Logout()\n        {\n            NotifyAuthenticationStateChanged(\n                Task.FromResult(new AuthenticationState(new ClaimsPrincipal())));\n        }\n    }\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Microsoft<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">AspNetCore<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Components<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Authorization<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">System<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Security<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Claims<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">namespace<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">BlazorSecurityDemo<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Authentication<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">class<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">UserAuthenticationStateProvider<\/span><span style=\"color: #24292E\"> : <\/span><span style=\"color: #6F42C1\">AuthenticationStateProvider<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">private<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">readonly<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">AuthenticationState<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">authenticationState<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">ClaimsPrincipal<\/span><span style=\"color: #24292E\">());<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">override<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Task<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #6F42C1\">AuthenticationState<\/span><span style=\"color: #24292E\">&gt; <\/span><span style=\"color: #6F42C1\">GetAuthenticationStateAsync<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> Task.<\/span><span style=\"color: #6F42C1\">FromResult<\/span><span style=\"color: #24292E\">(authenticationState);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">async<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Task<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #D73A49\">bool<\/span><span style=\"color: #24292E\">&gt; <\/span><span style=\"color: #6F42C1\">AuthenticateUserPasswordAsync<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">username<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">password<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #6A737D\">            \/\/ verify username and password<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">IList<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #6F42C1\">Claim<\/span><span style=\"color: #24292E\">&gt; <\/span><span style=\"color: #6F42C1\">claims<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> &#91;<\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Claim<\/span><span style=\"color: #24292E\">(ClaimTypes.Name, username)&#93;;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">identity<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">ClaimsIdentity<\/span><span style=\"color: #24292E\">(claims, <\/span><span style=\"color: #032F62\">&quot;AuthenticateUser&quot;<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">user<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">ClaimsPrincipal<\/span><span style=\"color: #24292E\">(identity);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">NotifyAuthenticationStateChanged<\/span><span style=\"color: #24292E\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                Task.<\/span><span style=\"color: #6F42C1\">FromResult<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">AuthenticationState<\/span><span style=\"color: #24292E\">(user)));<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">true<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">void<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Logout<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">NotifyAuthenticationStateChanged<\/span><span style=\"color: #24292E\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                Task.<\/span><span style=\"color: #6F42C1\">FromResult<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">AuthenticationState<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">ClaimsPrincipal<\/span><span style=\"color: #24292E\">())));<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The actual login code will be shown later on in this post. The <em>ClaimsIdentity <\/em>is created with an authentication type of &#8220;AuthenticateUser&#8221;. The actual value of this string doesn&#8217;t matter. The fact that it is not null means that the <em>ClaimsIdentity <\/em>will be marked as authenticated. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The <em>UserAuthenticationStateProvider <\/em>will need to be registered in <em>Program.cs<\/em> so that it will be used in the standard authentication process:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-highlight-color:rgba(16, 41, 67, 0.2);line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">C#<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>...    \nvar builder = WebApplication.CreateBuilder(args);\n\n\/\/ Add services to the container.\nbuilder.Services.AddRazorComponents().AddInteractiveServerComponents();\n\nbuilder.Services.AddAuthentication();\nbuilder.Services.AddCascadingAuthenticationState();\n\nbuilder.Services.\n    AddScoped&lt;AuthenticationStateProvider, UserAuthenticationStateProvider>();\n\nvar app = builder.Build();\n...\n<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D73A49\">..<\/span><span style=\"color: #24292E\">.    <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">builder<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> WebApplication.<\/span><span style=\"color: #6F42C1\">CreateBuilder<\/span><span style=\"color: #24292E\">(args);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6A737D\">\/\/ Add services to the container.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">builder.Services.<\/span><span style=\"color: #6F42C1\">AddRazorComponents<\/span><span style=\"color: #24292E\">().<\/span><span style=\"color: #6F42C1\">AddInteractiveServerComponents<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">builder.Services.<\/span><span style=\"color: #6F42C1\">AddAuthentication<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">builder.Services.<\/span><span style=\"color: #6F42C1\">AddCascadingAuthenticationState<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">builder.Services.<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #6F42C1\">AddScoped<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #6F42C1\">AuthenticationStateProvider<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #6F42C1\">UserAuthenticationStateProvider<\/span><span style=\"color: #24292E\">&gt;();<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">app<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> builder.<\/span><span style=\"color: #6F42C1\">Build<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">..<\/span><span style=\"color: #24292E\">.<\/span><\/span>\n<span class=\"line\"><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Our provider has been registered as a <em>scoped <\/em>service, which means that a separate instance will be created for each HTTP request. Since this app was created with render mode <em>Server <\/em>and interactivity location <em>Global<\/em>, interaction within the app including navigation is actually performed by modifying the DOM.  No HTTP requests are issued after the initial page load. Any navigation outside of the app or forcing the reload of a page via the browser controls will cause the <em>AuthenticationStateProvider <\/em>to be recreated, losing the previously established authentication state. Duplicating the tab with a running app in Microsoft Edge will cause a new HTTP request to be issued for the new tab, which means that the app in the new tab will not inherit the authentication of the current app. This is an important consideration for the security of this app.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Logging In and Out<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">To allow a user to log in to the server, we can borrow some of the code from the &#8220;Individual accounts&#8221; Blazor Web App template.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Add some includes to Components\/_Imports.razor:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-highlight-color:rgba(16, 41, 67, 0.2);line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">Razor<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>@using System.Net.Http\n@using System.Net.Http.Json\n@using Microsoft.AspNetCore.Authentication\n@using Microsoft.AspNetCore.Authorization\n@using Microsoft.AspNetCore.Components.Authorization\n@using Microsoft.AspNetCore.Components.Forms\n@using Microsoft.AspNetCore.Components.Routing\n@using Microsoft.AspNetCore.Components.Web\n@using static Microsoft.AspNetCore.Components.Web.RenderMode\n@using Microsoft.AspNetCore.Components.Web.Virtualization\n@using Microsoft.JSInterop\n@using System.ComponentModel.DataAnnotations\n@using System.Security.Claims\n@using System.Security.Principal\n@using BlazorSecurityDemo\n@using BlazorSecurityDemo.Authentication\n@using BlazorSecurityDemo.Components\n<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D73A49\">@using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">System<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Net<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Http<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">@using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">System<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Net<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Http<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Json<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D73A49\">@using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Microsoft<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">AspNetCore<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Authentication<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D73A49\">@using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Microsoft<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">AspNetCore<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Authorization<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D73A49\">@using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Microsoft<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">AspNetCore<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Components<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Authorization<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">@using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Microsoft<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">AspNetCore<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Components<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Forms<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">@using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Microsoft<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">AspNetCore<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Components<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Routing<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">@using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Microsoft<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">AspNetCore<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Components<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Web<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">@using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">static<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Microsoft<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">AspNetCore<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Components<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Web<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">RenderMode<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">@using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Microsoft<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">AspNetCore<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Components<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Web<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Virtualization<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">@using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Microsoft<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">JSInterop<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D73A49\">@using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">System<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">ComponentModel<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">DataAnnotations<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D73A49\">@using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">System<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Security<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Claims<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D73A49\">@using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">System<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Security<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Principal<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">@using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">BlazorSecurityDemo<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D73A49\">@using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">BlazorSecurityDemo<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Authentication<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">@using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">BlazorSecurityDemo<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Components<\/span><\/span>\n<span class=\"line\"><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Add <em>Components\/Pages\/StatusMessage.razor<\/em>:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">Razor<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>@if (!string.IsNullOrEmpty(Message))\n{\n    var statusMessageClass = Message.StartsWith(\"Error\") ? \"danger\" : \"success\";\n    &lt;div class=\"alert alert-@statusMessageClass\" role=\"alert\">\n        @Message\n    &lt;\/div>\n}\n\n@code {\n    &#91;Parameter&#93;\n    public string? Message { get; set; }\n}\n<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D73A49\">@if<\/span><span style=\"color: #24292E\"> (<\/span><span style=\"color: #D73A49\">!<\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">IsNullOrEmpty<\/span><span style=\"color: #24292E\">(Message))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">statusMessageClass<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> Message.<\/span><span style=\"color: #6F42C1\">StartsWith<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #032F62\">&quot;Error&quot;<\/span><span style=\"color: #24292E\">) <\/span><span style=\"color: #D73A49\">?<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;danger&quot;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">:<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;success&quot;<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    &lt;<\/span><span style=\"color: #22863A\">div<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">class<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;alert alert-@statusMessageClass&quot;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">role<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;alert&quot;<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">@<\/span><span style=\"color: #24292E\">Message<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    &lt;\/<\/span><span style=\"color: #22863A\">div<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">@code<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    &#91;<\/span><span style=\"color: #6F42C1\">Parameter<\/span><span style=\"color: #24292E\">&#93;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\">? <\/span><span style=\"color: #6F42C1\">Message<\/span><span style=\"color: #24292E\"> { <\/span><span style=\"color: #D73A49\">get<\/span><span style=\"color: #24292E\">; <\/span><span style=\"color: #D73A49\">set<\/span><span style=\"color: #24292E\">; }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">}<\/span><\/span>\n<span class=\"line\"><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Add <em>Components\/Pages\/Login.razor<\/em>:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">Razor<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>@page \"\/login\"\n\n@using System.Runtime.InteropServices;\n@inject AuthenticationStateProvider AuthenticationStateProvider\n\n&lt;PageTitle>Log in&lt;\/PageTitle>\n\n&lt;h1>Please log in to @serverName (@serverType) &lt;\/h1>\n\n&lt;div>\n    &lt;section>\n        &lt;StatusMessage Message=\"@passwordErrorMessage\"\/>\n        &lt;EditForm Model=\"passwordInput\" method=\"post\" \n                  OnValidSubmit=\"LoginWithPassword\" FormName=\"loginWithPassword\">\n            &lt;DataAnnotationsValidator\/>\n            &lt;h2>Use a server username and password to log in.&lt;\/h2>\n            &lt;hr\/>\n\n            &lt;ValidationSummary class=\"text-danger\" role=\"alert\"\/>\n            \n            &lt;div class=\"form-floating mb-3\">\n                &lt;InputText @bind-Value=\"passwordInput.Username\" \n                           class=\"form-control\" autocomplete=\"username\" \n                           aria-required=\"true\" placeholder=\"username\"\/>\n                &lt;label for=\"username\" class=\"form-label\">Username&lt;\/label>\n                &lt;ValidationMessage For=\"() => passwordInput.Username\" class=\"text-danger\"\/>\n            &lt;\/div>\n\n            &lt;div class=\"form-floating mb-3\">\n                &lt;InputText type=\"password\" @bind-Value=\"passwordInput.Password\" \n                           class=\"form-control\" autocomplete=\"password\" \n                           aria-required=\"true\" placeholder=\"password\"\/>\n                &lt;label for=\"password\" class=\"form-label\">Password&lt;\/label>\n                &lt;ValidationMessage For=\"() => passwordInput.Password\" class=\"text-danger\"\/>\n            &lt;\/div>\n\n            &lt;div>\n                &lt;button type=\"submit\" class=\"w-100 btn btn-log btn-primary\">Log in&lt;\/button>\n            &lt;\/div>\n        &lt;\/EditForm>\n    &lt;\/section>\n&lt;\/div>\n\n@code {\n    private string? serverName = Environment.MachineName;\n    private string? serverType = RuntimeInformation.RuntimeIdentifier;\n    private string? passwordErrorMessage = string.Empty;\n\n    &#91;SupplyParameterFromForm(FormName = \"loginWithPassword\")&#93;\n    private PasswordInputModel passwordInput { get; set; } = new();\n\n    protected async Task LoginWithPassword()\n    {\n        if (AuthenticationStateProvider is UserAuthenticationStateProvider auth)\n        {\n            var success = await auth.AuthenticateUserPasswordAsync(\n                passwordInput.Username, passwordInput.Password);\n\n            if (success)\n            {\n                passwordErrorMessage = \"Logged in\";\n            }\n            else\n            {\n                passwordErrorMessage = \"Error: invalid username\/password\";\n            }\n        }\n    }\n\n    private sealed class PasswordInputModel\n    {\n        &#91;Required&#93;\n        public string Username { get; set; } = string.Empty;\n\n        &#91;Required&#93;\n        &#91;DataType(DataType.Password)&#93;\n        public string Password { get; set; } = string.Empty;\n    }\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D73A49\">@page<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;\/login&quot;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">@using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">System<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Runtime<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">InteropServices<\/span><span style=\"color: #D73A49\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">@inject<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">AuthenticationStateProvider<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">AuthenticationStateProvider<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #B31D28; font-style: italic\">PageTitle<\/span><span style=\"color: #24292E\">&gt;Log in&lt;\/<\/span><span style=\"color: #B31D28; font-style: italic\">PageTitle<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #22863A\">h1<\/span><span style=\"color: #24292E\">&gt;Please log in to <\/span><span style=\"color: #D73A49\">@<\/span><span style=\"color: #24292E\">serverName (<\/span><span style=\"color: #D73A49\">@<\/span><span style=\"color: #24292E\">serverType) &lt;\/<\/span><span style=\"color: #22863A\">h1<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #22863A\">div<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    &lt;<\/span><span style=\"color: #22863A\">section<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        &lt;<\/span><span style=\"color: #B31D28; font-style: italic\">StatusMessage<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Message<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;@passwordErrorMessage&quot;<\/span><span style=\"color: #24292E\">\/&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        &lt;<\/span><span style=\"color: #B31D28; font-style: italic\">EditForm<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Model<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;passwordInput&quot;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">method<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;post&quot;<\/span><span style=\"color: #24292E\"> <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                  <\/span><span style=\"color: #6F42C1\">OnValidSubmit<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;LoginWithPassword&quot;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">FormName<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;loginWithPassword&quot;<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            &lt;<\/span><span style=\"color: #B31D28; font-style: italic\">DataAnnotationsValidator<\/span><span style=\"color: #24292E\">\/&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            &lt;<\/span><span style=\"color: #22863A\">h2<\/span><span style=\"color: #24292E\">&gt;Use a server username and password to log in.&lt;\/<\/span><span style=\"color: #22863A\">h2<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            &lt;<\/span><span style=\"color: #22863A\">hr<\/span><span style=\"color: #24292E\">\/&gt;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            &lt;<\/span><span style=\"color: #B31D28; font-style: italic\">ValidationSummary<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">class<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;text-danger&quot;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">role<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;alert&quot;<\/span><span style=\"color: #24292E\">\/&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            &lt;<\/span><span style=\"color: #22863A\">div<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">class<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;form-floating mb-3&quot;<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                &lt;<\/span><span style=\"color: #B31D28; font-style: italic\">InputText<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">@bind-Value<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;passwordInput.Username&quot;<\/span><span style=\"color: #24292E\"> <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                           <\/span><span style=\"color: #6F42C1\">class<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;form-control&quot;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">autocomplete<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;username&quot;<\/span><span style=\"color: #24292E\"> <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                           <\/span><span style=\"color: #6F42C1\">aria-required<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;true&quot;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">placeholder<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;username&quot;<\/span><span style=\"color: #24292E\">\/&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                &lt;<\/span><span style=\"color: #22863A\">label<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">for<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;username&quot;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">class<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;form-label&quot;<\/span><span style=\"color: #24292E\">&gt;Username&lt;\/<\/span><span style=\"color: #22863A\">label<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                &lt;<\/span><span style=\"color: #B31D28; font-style: italic\">ValidationMessage<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">For<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;() =&gt; passwordInput.Username&quot;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">class<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;text-danger&quot;<\/span><span style=\"color: #24292E\">\/&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            &lt;\/<\/span><span style=\"color: #22863A\">div<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            &lt;<\/span><span style=\"color: #22863A\">div<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">class<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;form-floating mb-3&quot;<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                &lt;<\/span><span style=\"color: #B31D28; font-style: italic\">InputText<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">type<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;password&quot;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">@bind-Value<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;passwordInput.Password&quot;<\/span><span style=\"color: #24292E\"> <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                           <\/span><span style=\"color: #6F42C1\">class<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;form-control&quot;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">autocomplete<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;password&quot;<\/span><span style=\"color: #24292E\"> <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                           <\/span><span style=\"color: #6F42C1\">aria-required<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;true&quot;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">placeholder<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;password&quot;<\/span><span style=\"color: #24292E\">\/&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                &lt;<\/span><span style=\"color: #22863A\">label<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">for<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;password&quot;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">class<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;form-label&quot;<\/span><span style=\"color: #24292E\">&gt;Password&lt;\/<\/span><span style=\"color: #22863A\">label<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                &lt;<\/span><span style=\"color: #B31D28; font-style: italic\">ValidationMessage<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">For<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;() =&gt; passwordInput.Password&quot;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">class<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;text-danger&quot;<\/span><span style=\"color: #24292E\">\/&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            &lt;\/<\/span><span style=\"color: #22863A\">div<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            &lt;<\/span><span style=\"color: #22863A\">div<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                &lt;<\/span><span style=\"color: #22863A\">button<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">type<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;submit&quot;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">class<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;w-100 btn btn-log btn-primary&quot;<\/span><span style=\"color: #24292E\">&gt;Log in&lt;\/<\/span><span style=\"color: #22863A\">button<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            &lt;\/<\/span><span style=\"color: #22863A\">div<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        &lt;\/<\/span><span style=\"color: #B31D28; font-style: italic\">EditForm<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    &lt;\/<\/span><span style=\"color: #22863A\">section<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">&lt;\/<\/span><span style=\"color: #22863A\">div<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">@code<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">private<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\">? <\/span><span style=\"color: #6F42C1\">serverName<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> Environment.MachineName;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">private<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\">? <\/span><span style=\"color: #6F42C1\">serverType<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> RuntimeInformation.RuntimeIdentifier;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">private<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\">? <\/span><span style=\"color: #6F42C1\">passwordErrorMessage<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\">.Empty;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    &#91;<\/span><span style=\"color: #6F42C1\">SupplyParameterFromForm<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">FormName<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;loginWithPassword&quot;<\/span><span style=\"color: #24292E\">)&#93;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">private<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">PasswordInputModel<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">passwordInput<\/span><span style=\"color: #24292E\"> { <\/span><span style=\"color: #D73A49\">get<\/span><span style=\"color: #24292E\">; <\/span><span style=\"color: #D73A49\">set<\/span><span style=\"color: #24292E\">; } <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">protected<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">async<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Task<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">LoginWithPassword<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (AuthenticationStateProvider <\/span><span style=\"color: #D73A49\">is<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">UserAuthenticationStateProvider<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">auth<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">success<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">await<\/span><span style=\"color: #24292E\"> auth.<\/span><span style=\"color: #6F42C1\">AuthenticateUserPasswordAsync<\/span><span style=\"color: #24292E\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                passwordInput.Username, passwordInput.Password);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (success)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                passwordErrorMessage <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;Logged in&quot;<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">else<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                passwordErrorMessage <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;Error: invalid username\/password&quot;<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">private<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">sealed<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">class<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">PasswordInputModel<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        &#91;<\/span><span style=\"color: #6F42C1\">Required<\/span><span style=\"color: #24292E\">&#93;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Username<\/span><span style=\"color: #24292E\"> { <\/span><span style=\"color: #D73A49\">get<\/span><span style=\"color: #24292E\">; <\/span><span style=\"color: #D73A49\">set<\/span><span style=\"color: #24292E\">; } <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\">.Empty;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        &#91;<\/span><span style=\"color: #6F42C1\">Required<\/span><span style=\"color: #24292E\">&#93;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        &#91;<\/span><span style=\"color: #6F42C1\">DataType<\/span><span style=\"color: #24292E\">(DataType.Password)&#93;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Password<\/span><span style=\"color: #24292E\"> { <\/span><span style=\"color: #D73A49\">get<\/span><span style=\"color: #24292E\">; <\/span><span style=\"color: #D73A49\">set<\/span><span style=\"color: #24292E\">; } <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\">.Empty;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I put in a heading describing the server being logged into to help with knowing when the app is running in a debugging environment.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Add a reference to the login page to the navigation bar <em>Components\/Layout\/NavMenu.razor<\/em>:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-highlight-color:rgba(16, 41, 67, 0.2);line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">Razor<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>...\n&lt;div class=\"nav-scrollable\" onclick=\"document.querySelector('.navbar-toggler').click()\">\n    &lt;nav class=\"nav flex-column\">\n        &lt;div class=\"nav-item px-3\">\n            &lt;NavLink class=\"nav-link\" href=\"home\" Match=\"NavLinkMatch.All\">\n                &lt;span class=\"bi bi-house-door-fill-nav-menu\" aria-hidden=\"true\">&lt;\/span> Home\n            &lt;\/NavLink>\n        &lt;\/div>\n\n        &lt;div class=\"nav-item px-3\">\n            &lt;NavLink class=\"nav-link\" href=\"login\" Match=\"NavLinkMatch.All\">\n                &lt;span class=\"bi bi-house-door-fill-nav-menu\" aria-hidden=\"true\">&lt;\/span> Login\n            &lt;\/NavLink>\n        &lt;\/div>\n    &lt;\/nav>\n&lt;\/div>\n...<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #24292E\">...<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #22863A\">div<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">class<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;nav-scrollable&quot;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">onclick<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;document.querySelector(&#39;.navbar-toggler&#39;).click()&quot;<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    &lt;<\/span><span style=\"color: #22863A\">nav<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">class<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;nav flex-column&quot;<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        &lt;<\/span><span style=\"color: #22863A\">div<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">class<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;nav-item px-3&quot;<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            &lt;<\/span><span style=\"color: #B31D28; font-style: italic\">NavLink<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">class<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;nav-link&quot;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">href<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;home&quot;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Match<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;NavLinkMatch.All&quot;<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                &lt;<\/span><span style=\"color: #22863A\">span<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">class<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;bi bi-house-door-fill-nav-menu&quot;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">aria-hidden<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;true&quot;<\/span><span style=\"color: #24292E\">&gt;&lt;\/<\/span><span style=\"color: #22863A\">span<\/span><span style=\"color: #24292E\">&gt; Home<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            &lt;\/<\/span><span style=\"color: #B31D28; font-style: italic\">NavLink<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        &lt;\/<\/span><span style=\"color: #22863A\">div<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">        &lt;<\/span><span style=\"color: #22863A\">div<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">class<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;nav-item px-3&quot;<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">            &lt;<\/span><span style=\"color: #B31D28; font-style: italic\">NavLink<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">class<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;nav-link&quot;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">href<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;login&quot;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Match<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;NavLinkMatch.All&quot;<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">                &lt;<\/span><span style=\"color: #22863A\">span<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">class<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;bi bi-house-door-fill-nav-menu&quot;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">aria-hidden<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;true&quot;<\/span><span style=\"color: #24292E\">&gt;&lt;\/<\/span><span style=\"color: #22863A\">span<\/span><span style=\"color: #24292E\">&gt; Login<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">            &lt;\/<\/span><span style=\"color: #B31D28; font-style: italic\">NavLink<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">        &lt;\/<\/span><span style=\"color: #22863A\">div<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    &lt;\/<\/span><span style=\"color: #22863A\">nav<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">&lt;\/<\/span><span style=\"color: #22863A\">div<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">...<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The login page does function, although there is no verification of the username and password and the results are difficult to see.  We can create a simple status page to provide some feedback:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-highlight-color:rgba(16, 41, 67, 0.2);line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">Razor<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>@page \"\/userDetails\"\n\n&lt;PageTitle>UserDetails&lt;\/PageTitle>\n\n&lt;h3>User Details&lt;\/h3>\n\n&lt;AuthorizeView>\n    &lt;Authorized>\n        &lt;label>Claims for @context.User.Identity?.Name&lt;\/label>\n        &lt;br \/>\n        &lt;table class=\"table\">\n            &lt;thead>\n                &lt;tr>\n                    &lt;th>Type&lt;\/th>\n                    &lt;th>Value&lt;\/th>\n                &lt;\/tr>\n            &lt;\/thead>\n            &lt;tbody>\n                @foreach (var claim in context.User.Claims)\n                {\n                    &lt;tr>\n                        &lt;td>@claim.Type&lt;\/td>\n                        &lt;td>@claim.Value&lt;\/td>\n                    &lt;\/tr>\n                }\n            &lt;\/tbody>\n        &lt;\/table>\n    &lt;\/Authorized>\n    &lt;NotAuthorized>\n        Please &lt;a href=\"login\">log in&lt;\/a>.\n    &lt;\/NotAuthorized>\n&lt;\/AuthorizeView>\n\n@code {\n\n}\n<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D73A49\">@page<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;\/userDetails&quot;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #B31D28; font-style: italic\">PageTitle<\/span><span style=\"color: #24292E\">&gt;UserDetails&lt;\/<\/span><span style=\"color: #B31D28; font-style: italic\">PageTitle<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #22863A\">h3<\/span><span style=\"color: #24292E\">&gt;User Details&lt;\/<\/span><span style=\"color: #22863A\">h3<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #B31D28; font-style: italic\">AuthorizeView<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">    &lt;<\/span><span style=\"color: #B31D28; font-style: italic\">Authorized<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        &lt;<\/span><span style=\"color: #22863A\">label<\/span><span style=\"color: #24292E\">&gt;Claims for <\/span><span style=\"color: #D73A49\">@<\/span><span style=\"color: #24292E\">context.User.Identity?.Name&lt;\/<\/span><span style=\"color: #22863A\">label<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        &lt;<\/span><span style=\"color: #22863A\">br<\/span><span style=\"color: #24292E\"> \/&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        &lt;<\/span><span style=\"color: #22863A\">table<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">class<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;table&quot;<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            &lt;<\/span><span style=\"color: #22863A\">thead<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                &lt;<\/span><span style=\"color: #22863A\">tr<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    &lt;<\/span><span style=\"color: #22863A\">th<\/span><span style=\"color: #24292E\">&gt;Type&lt;\/<\/span><span style=\"color: #22863A\">th<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    &lt;<\/span><span style=\"color: #22863A\">th<\/span><span style=\"color: #24292E\">&gt;Value&lt;\/<\/span><span style=\"color: #22863A\">th<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                &lt;\/<\/span><span style=\"color: #22863A\">tr<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            &lt;\/<\/span><span style=\"color: #22863A\">thead<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            &lt;<\/span><span style=\"color: #22863A\">tbody<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #D73A49\">@foreach<\/span><span style=\"color: #24292E\"> (<\/span><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">claim<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">in<\/span><span style=\"color: #24292E\"> context.User.Claims)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    &lt;<\/span><span style=\"color: #22863A\">tr<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                        &lt;<\/span><span style=\"color: #22863A\">td<\/span><span style=\"color: #24292E\">&gt;<\/span><span style=\"color: #D73A49\">@<\/span><span style=\"color: #24292E\">claim.Type&lt;\/<\/span><span style=\"color: #22863A\">td<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                        &lt;<\/span><span style=\"color: #22863A\">td<\/span><span style=\"color: #24292E\">&gt;<\/span><span style=\"color: #D73A49\">@<\/span><span style=\"color: #24292E\">claim.Value&lt;\/<\/span><span style=\"color: #22863A\">td<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    &lt;\/<\/span><span style=\"color: #22863A\">tr<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            &lt;\/<\/span><span style=\"color: #22863A\">tbody<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        &lt;\/<\/span><span style=\"color: #22863A\">table<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">    &lt;\/<\/span><span style=\"color: #B31D28; font-style: italic\">Authorized<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">    &lt;<\/span><span style=\"color: #B31D28; font-style: italic\">NotAuthorized<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        Please &lt;<\/span><span style=\"color: #22863A\">a<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">href<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;login&quot;<\/span><span style=\"color: #24292E\">&gt;log in&lt;\/<\/span><span style=\"color: #22863A\">a<\/span><span style=\"color: #24292E\">&gt;.<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">    &lt;\/<\/span><span style=\"color: #B31D28; font-style: italic\">NotAuthorized<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">&lt;\/<\/span><span style=\"color: #B31D28; font-style: italic\">AuthorizeView<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">@code<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">{<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">}<\/span><\/span>\n<span class=\"line\"><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">The <em>AuthorizeView <\/em>component controls what content is displayed depending on the authentication state. The <em>Authorized <\/em>component only displays its content if the current state is authorized, while the <em>NotAuthorized <\/em>component only displays its content if the state is not authorized. By default &#8220;authorized&#8221; means that the <em>ClaimsPrincipal <\/em>primary identity is authenticated. The <em>AuthorizeView <\/em>component exposes a <em>context <\/em>variable<em> <\/em>of type <em>AuthenticationState<\/em>. This is used in the authorized page content to display some information about the logged in user.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A page to log the user out completes the authentication suite.  Create <em>Components\/Pages\/Logout.razor<\/em>:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">Razor<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>@page \"\/logout\"\n\n@inject AuthenticationStateProvider AuthenticationStateProvider\n@inject NavigationManager NavigationManager\n\n&lt;h3>Logout&lt;\/h3>\n\n@code {\n    protected override void OnParametersSet()\n    {\n        if (AuthenticationStateProvider is UserAuthenticationStateProvider auth)\n        {\n            auth.Logout();\n        }\n\n        NavigationManager.NavigateTo(\"login\");\n    }\n}\n<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D73A49\">@page<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;\/logout&quot;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">@inject<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">AuthenticationStateProvider<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">AuthenticationStateProvider<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">@inject<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">NavigationManager<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">NavigationManager<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #22863A\">h3<\/span><span style=\"color: #24292E\">&gt;Logout&lt;\/<\/span><span style=\"color: #22863A\">h3<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">@code<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">protected<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">override<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">void<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">OnParametersSet<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (AuthenticationStateProvider <\/span><span style=\"color: #D73A49\">is<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">UserAuthenticationStateProvider<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">auth<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            auth.<\/span><span style=\"color: #6F42C1\">Logout<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        NavigationManager.<\/span><span style=\"color: #6F42C1\">NavigateTo<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #032F62\">&quot;login&quot;<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">}<\/span><\/span>\n<span class=\"line\"><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">This page does not display. It logs the user out and redirects to the login page immediately. You could modify this to provide a warning message with a commit button.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The <em>AuthorizeView <\/em>component can also be used in the navigation bar to control what page links are visible. We can change it to only display the Login page when logged out and only display the Logout page when logged in.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Modify <em>Components\/Pages\/Login.razor<\/em> to redirect to the UserDetails page on success:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-highlight-color:rgba(16, 41, 67, 0.2);line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">Razor<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>@page \"\/login\"\n\n@using System.Runtime.InteropServices;\n@inject AuthenticationStateProvider AuthenticationStateProvider\n@inject NavigationManager NavigationManager\n\n&lt;PageTitle>Log in&lt;\/PageTitle>\n...\n@code {\n...\n    protected async Task LoginWithPassword()\n    {\n        if (AuthenticationStateProvider is UserAuthenticationStateProvider auth)\n        {\n            var success = await auth.AuthenticateUserPasswordAsync(\n                passwordInput.Username, passwordInput.Password);\n\n            if (success)\n            {\n                passwordErrorMessage = \"Logged in\";\n                NavigationManager.NavigateTo(\"userDetails\");\n            }\n            else\n            {\n                passwordErrorMessage = \"Error: invalid username\/password\";\n            }\n        }\n    }\n...<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D73A49\">@page<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;\/login&quot;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">@using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">System<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Runtime<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">InteropServices<\/span><span style=\"color: #D73A49\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">@inject<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">AuthenticationStateProvider<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">AuthenticationStateProvider<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D73A49\">@inject<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">NavigationManager<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">NavigationManager<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #B31D28; font-style: italic\">PageTitle<\/span><span style=\"color: #24292E\">&gt;Log in&lt;\/<\/span><span style=\"color: #B31D28; font-style: italic\">PageTitle<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">...<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">@code<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">...<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">protected<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">async<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Task<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">LoginWithPassword<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (AuthenticationStateProvider <\/span><span style=\"color: #D73A49\">is<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">UserAuthenticationStateProvider<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">auth<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">success<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">await<\/span><span style=\"color: #24292E\"> auth.<\/span><span style=\"color: #6F42C1\">AuthenticateUserPasswordAsync<\/span><span style=\"color: #24292E\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                passwordInput.Username, passwordInput.Password);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (success)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                passwordErrorMessage <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;Logged in&quot;<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">                NavigationManager.<\/span><span style=\"color: #6F42C1\">NavigateTo<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #032F62\">&quot;userDetails&quot;<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">else<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                passwordErrorMessage <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;Error: invalid username\/password&quot;<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">...<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Modify Components\/Layout\/NavMenu.razor to selectively show the page links:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">Razor<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>&lt;div class=\"top-row ps-3 navbar navbar-dark\">\n    &lt;div class=\"container-fluid\">\n        &lt;a class=\"navbar-brand\" href=\"\">BlazorSecurityDemo&lt;\/a>\n    &lt;\/div>\n&lt;\/div>\n\n&lt;input type=\"checkbox\" title=\"Navigation menu\" class=\"navbar-toggler\" \/>\n\n&lt;div class=\"nav-scrollable\" onclick=\"document.querySelector('.navbar-toggler').click()\">\n    &lt;nav class=\"nav flex-column\">\n        &lt;div class=\"nav-item px-3\">\n            &lt;NavLink class=\"nav-link\" href=\"home\" Match=\"NavLinkMatch.All\">\n                &lt;span class=\"bi bi-house-door-fill-nav-menu\" aria-hidden=\"true\">&lt;\/span> Home\n            &lt;\/NavLink>\n        &lt;\/div>\n\n        &lt;AuthorizeView>\n            &lt;Authorized>\n                &lt;div class=\"nav-item px-3\">\n                    &lt;NavLink class=\"nav-link\" href=\"userdetails\" Match=\"NavLinkMatch.All\">\n                        &lt;span class=\"bi bi-plus-square-fill-nav-menu\" aria-hidden=\"true\">&lt;\/span> User Details\n                    &lt;\/NavLink>\n                &lt;\/div>\n\n                &lt;div class=\"nav-item px-3\">\n                    &lt;NavLink class=\"nav-link\" href=\"logout\">\n                        &lt;span class=\"bi bi-arrow-bar-left-nav-menu\" aria-hidden=\"true\">&lt;\/span> Logout\n                    &lt;\/NavLink>\n                &lt;\/div>\n            &lt;\/Authorized>\n            &lt;NotAuthorized>\n                &lt;div class=\"nav-item px-3\">\n                    &lt;NavLink class=\"nav-link\" href=\"login\" Match=\"NavLinkMatch.All\">\n                        &lt;span class=\"bi bi-person-badge-nav-menu\" aria-hidden=\"true\">&lt;\/span> Login\n                    &lt;\/NavLink>\n                &lt;\/div>\n            &lt;\/NotAuthorized>\n        &lt;\/AuthorizeView>\n    &lt;\/nav>\n&lt;\/div><\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #22863A\">div<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">class<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;top-row ps-3 navbar navbar-dark&quot;<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    &lt;<\/span><span style=\"color: #22863A\">div<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">class<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;container-fluid&quot;<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        &lt;<\/span><span style=\"color: #22863A\">a<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">class<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;navbar-brand&quot;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">href<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;&quot;<\/span><span style=\"color: #24292E\">&gt;BlazorSecurityDemo&lt;\/<\/span><span style=\"color: #22863A\">a<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    &lt;\/<\/span><span style=\"color: #22863A\">div<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">&lt;\/<\/span><span style=\"color: #22863A\">div<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #22863A\">input<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">type<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;checkbox&quot;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">title<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;Navigation menu&quot;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">class<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;navbar-toggler&quot;<\/span><span style=\"color: #24292E\"> \/&gt;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #22863A\">div<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">class<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;nav-scrollable&quot;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">onclick<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;document.querySelector(&#39;.navbar-toggler&#39;).click()&quot;<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    &lt;<\/span><span style=\"color: #22863A\">nav<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">class<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;nav flex-column&quot;<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        &lt;<\/span><span style=\"color: #22863A\">div<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">class<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;nav-item px-3&quot;<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            &lt;<\/span><span style=\"color: #B31D28; font-style: italic\">NavLink<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">class<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;nav-link&quot;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">href<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;home&quot;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Match<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;NavLinkMatch.All&quot;<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                &lt;<\/span><span style=\"color: #22863A\">span<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">class<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;bi bi-house-door-fill-nav-menu&quot;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">aria-hidden<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;true&quot;<\/span><span style=\"color: #24292E\">&gt;&lt;\/<\/span><span style=\"color: #22863A\">span<\/span><span style=\"color: #24292E\">&gt; Home<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            &lt;\/<\/span><span style=\"color: #B31D28; font-style: italic\">NavLink<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        &lt;\/<\/span><span style=\"color: #22863A\">div<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        &lt;<\/span><span style=\"color: #B31D28; font-style: italic\">AuthorizeView<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            &lt;<\/span><span style=\"color: #B31D28; font-style: italic\">Authorized<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                &lt;<\/span><span style=\"color: #22863A\">div<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">class<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;nav-item px-3&quot;<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    &lt;<\/span><span style=\"color: #B31D28; font-style: italic\">NavLink<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">class<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;nav-link&quot;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">href<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;userdetails&quot;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Match<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;NavLinkMatch.All&quot;<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                        &lt;<\/span><span style=\"color: #22863A\">span<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">class<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;bi bi-plus-square-fill-nav-menu&quot;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">aria-hidden<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;true&quot;<\/span><span style=\"color: #24292E\">&gt;&lt;\/<\/span><span style=\"color: #22863A\">span<\/span><span style=\"color: #24292E\">&gt; User Details<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    &lt;\/<\/span><span style=\"color: #B31D28; font-style: italic\">NavLink<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                &lt;\/<\/span><span style=\"color: #22863A\">div<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                &lt;<\/span><span style=\"color: #22863A\">div<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">class<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;nav-item px-3&quot;<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    &lt;<\/span><span style=\"color: #B31D28; font-style: italic\">NavLink<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">class<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;nav-link&quot;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">href<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;logout&quot;<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                        &lt;<\/span><span style=\"color: #22863A\">span<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">class<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;bi bi-arrow-bar-left-nav-menu&quot;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">aria-hidden<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;true&quot;<\/span><span style=\"color: #24292E\">&gt;&lt;\/<\/span><span style=\"color: #22863A\">span<\/span><span style=\"color: #24292E\">&gt; Logout<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    &lt;\/<\/span><span style=\"color: #B31D28; font-style: italic\">NavLink<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                &lt;\/<\/span><span style=\"color: #22863A\">div<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            &lt;\/<\/span><span style=\"color: #B31D28; font-style: italic\">Authorized<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            &lt;<\/span><span style=\"color: #B31D28; font-style: italic\">NotAuthorized<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                &lt;<\/span><span style=\"color: #22863A\">div<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">class<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;nav-item px-3&quot;<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    &lt;<\/span><span style=\"color: #B31D28; font-style: italic\">NavLink<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">class<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;nav-link&quot;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">href<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;login&quot;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Match<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;NavLinkMatch.All&quot;<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                        &lt;<\/span><span style=\"color: #22863A\">span<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">class<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;bi bi-person-badge-nav-menu&quot;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">aria-hidden<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;true&quot;<\/span><span style=\"color: #24292E\">&gt;&lt;\/<\/span><span style=\"color: #22863A\">span<\/span><span style=\"color: #24292E\">&gt; Login<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    &lt;\/<\/span><span style=\"color: #B31D28; font-style: italic\">NavLink<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                &lt;\/<\/span><span style=\"color: #22863A\">div<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            &lt;\/<\/span><span style=\"color: #B31D28; font-style: italic\">NotAuthorized<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        &lt;\/<\/span><span style=\"color: #B31D28; font-style: italic\">AuthorizeView<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    &lt;\/<\/span><span style=\"color: #22863A\">nav<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">&lt;\/<\/span><span style=\"color: #22863A\">div<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I borrowed the extra navigation bar icons from the &#8220;Individual accounts&#8221; template and placed them in <em>Components\/Layout\/NavMenu.razor.css<\/em>:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-highlight-color:rgba(16, 41, 67, 0.2);line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">CSS<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>...\n.bi-house-door-fill-nav-menu {\n    background-image: url(\"data:image\/svg+xml,%3Csvg xmlns='http:\/\/www.w3.org\/2000\/svg' width='16' height='16' fill='white' class='bi bi-house-door-fill' viewBox='0 0 16 16'%3E%3Cpath d='M6.5 14.5v-3.505c0-.245.25-.495.5-.495h2c.25 0 .5.25.5.5v3.5a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5v-7a.5.5 0 0 0-.146-.354L13 5.793V2.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1.293L8.354 1.146a.5.5 0 0 0-.708 0l-6 6A.5.5 0 0 0 1.5 7.5v7a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5Z'\/%3E%3C\/svg%3E\");\n}\n\n.bi-plus-square-fill-nav-menu {\n    background-image: url(\"data:image\/svg+xml,%3Csvg xmlns='http:\/\/www.w3.org\/2000\/svg' width='16' height='16' fill='white' class='bi bi-plus-square-fill' viewBox='0 0 16 16'%3E%3Cpath d='M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2zm6.5 4.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3a.5.5 0 0 1 1 0z'\/%3E%3C\/svg%3E\");\n}\n\n.bi-list-nested-nav-menu {\n    background-image: url(\"data:image\/svg+xml,%3Csvg xmlns='http:\/\/www.w3.org\/2000\/svg' width='16' height='16' fill='white' class='bi bi-list-nested' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M4.5 11.5A.5.5 0 0 1 5 11h10a.5.5 0 0 1 0 1H5a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 3 7h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 1 3h10a.5.5 0 0 1 0 1H1a.5.5 0 0 1-.5-.5z'\/%3E%3C\/svg%3E\");\n}\n\n.bi-person-badge-nav-menu {\n    background-image: url(\"data:image\/svg+xml,%3Csvg xmlns='http:\/\/www.w3.org\/2000\/svg' width='16' height='16' fill='white' class='bi bi-person-badge' viewBox='0 0 16 16'%3E%3Cpath d='M6.5 2a.5.5 0 0 0 0 1h3a.5.5 0 0 0 0-1h-3zM11 8a3 3 0 1 1-6 0 3 3 0 0 1 6 0z'\/%3E%3Cpath d='M4.5 0A2.5 2.5 0 0 0 2 2.5V14a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V2.5A2.5 2.5 0 0 0 11.5 0h-7zM3 2.5A1.5 1.5 0 0 1 4.5 1h7A1.5 1.5 0 0 1 13 2.5v10.795a4.2 4.2 0 0 0-.776-.492C11.392 12.387 10.063 12 8 12s-3.392.387-4.224.803a4.2 4.2 0 0 0-.776.492V2.5z'\/%3E%3C\/svg%3E\");\n}\n\n.bi-person-fill-nav-menu {\n    background-image: url(\"data:image\/svg+xml,%3Csvg xmlns='http:\/\/www.w3.org\/2000\/svg' width='16' height='16' fill='white' class='bi bi-person-fill' viewBox='0 0 16 16'%3E%3Cpath d='M3 14s-1 0-1-1 1-4 6-4 6 3 6 4-1 1-1 1H3Zm5-6a3 3 0 1 0 0-6 3 3 0 0 0 0 6Z'\/%3E%3C\/svg%3E\");\n}\n\n.bi-arrow-bar-left-nav-menu {\n    background-image: url(\"data:image\/svg+xml,%3Csvg xmlns='http:\/\/www.w3.org\/2000\/svg' width='16' height='16' fill='white' class='bi bi-arrow-bar-left' viewBox='0 0 16 16'%3E%3Cpath d='M12.5 15a.5.5 0 0 1-.5-.5v-13a.5.5 0 0 1 1 0v13a.5.5 0 0 1-.5.5ZM10 8a.5.5 0 0 1-.5.5H3.707l2.147 2.146a.5.5 0 0 1-.708.708l-3-3a.5.5 0 0 1 0-.708l3-3a.5.5 0 1 1 .708.708L3.707 7.5H9.5a.5.5 0 0 1 .5.5Z'\/%3E%3C\/svg%3E\");\n}\n\n.bi-detail-nav-menu {\n    background-image: url(\"data:image\/svg+xml, %3Csvg xmlns='http:\/\/www.w3.org\/2000\/svg' width='16' height='16' fill='white' class='bi bi-card-text' viewBox='0 0 16 16'%3E %3Cpath d='M14.5 3a.5.5 0 0 1 .5.5v9a.5.5 0 0 1-.5.5h-13a.5.5 0 0 1-.5-.5v-9a.5.5 0 0 1 .5-.5zm-13-1A1.5 1.5 0 0 0 0 3.5v9A1.5 1.5 0 0 0 1.5 14h13a1.5 1.5 0 0 0 1.5-1.5v-9A1.5 1.5 0 0 0 14.5 2z'\/%3E %3Cpath d='M3 5.5a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5M3 8a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9A.5.5 0 0 1 3 8m0 2.5a.5.5 0 0 1 .5-.5h6a.5.5 0 0 1 0 1h-6a.5.5 0 0 1-.5-.5'\/%3E %3C\/svg%3E\")\n}\n\n.nav-item {\n    font-size: 0.9rem;\n    padding-bottom: 0.5rem;\n}\n...<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #24292E\">...<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6F42C1\">.bi-house-door-fill-nav-menu<\/span><span style=\"color: #24292E\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #005CC5\">background-image<\/span><span style=\"color: #24292E\">: <\/span><span style=\"color: #005CC5\">url<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #032F62\">&quot;data:image\/svg+xml,%3Csvg xmlns=&#39;http:\/\/www.w3.org\/2000\/svg&#39; width=&#39;16&#39; height=&#39;16&#39; fill=&#39;white&#39; class=&#39;bi bi-house-door-fill&#39; viewBox=&#39;0 0 16 16&#39;%3E%3Cpath d=&#39;M6.5 14.5v-3.505c0-.245.25-.495.5-.495h2c.25 0 .5.25.5.5v3.5a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5v-7a.5.5 0 0 0-.146-.354L13 5.793V2.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1.293L8.354 1.146a.5.5 0 0 0-.708 0l-6 6A.5.5 0 0 0 1.5 7.5v7a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5Z&#39;\/%3E%3C\/svg%3E&quot;<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6F42C1\">.bi-plus-square-fill-nav-menu<\/span><span style=\"color: #24292E\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #005CC5\">background-image<\/span><span style=\"color: #24292E\">: <\/span><span style=\"color: #005CC5\">url<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #032F62\">&quot;data:image\/svg+xml,%3Csvg xmlns=&#39;http:\/\/www.w3.org\/2000\/svg&#39; width=&#39;16&#39; height=&#39;16&#39; fill=&#39;white&#39; class=&#39;bi bi-plus-square-fill&#39; viewBox=&#39;0 0 16 16&#39;%3E%3Cpath d=&#39;M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2zm6.5 4.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3a.5.5 0 0 1 1 0z&#39;\/%3E%3C\/svg%3E&quot;<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6F42C1\">.bi-list-nested-nav-menu<\/span><span style=\"color: #24292E\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #005CC5\">background-image<\/span><span style=\"color: #24292E\">: <\/span><span style=\"color: #005CC5\">url<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #032F62\">&quot;data:image\/svg+xml,%3Csvg xmlns=&#39;http:\/\/www.w3.org\/2000\/svg&#39; width=&#39;16&#39; height=&#39;16&#39; fill=&#39;white&#39; class=&#39;bi bi-list-nested&#39; viewBox=&#39;0 0 16 16&#39;%3E%3Cpath fill-rule=&#39;evenodd&#39; d=&#39;M4.5 11.5A.5.5 0 0 1 5 11h10a.5.5 0 0 1 0 1H5a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 3 7h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 1 3h10a.5.5 0 0 1 0 1H1a.5.5 0 0 1-.5-.5z&#39;\/%3E%3C\/svg%3E&quot;<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #6F42C1\">.bi-person-badge-nav-menu<\/span><span style=\"color: #24292E\"> {<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #005CC5\">background-image<\/span><span style=\"color: #24292E\">: <\/span><span style=\"color: #005CC5\">url<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #032F62\">&quot;data:image\/svg+xml,%3Csvg xmlns=&#39;http:\/\/www.w3.org\/2000\/svg&#39; width=&#39;16&#39; height=&#39;16&#39; fill=&#39;white&#39; class=&#39;bi bi-person-badge&#39; viewBox=&#39;0 0 16 16&#39;%3E%3Cpath d=&#39;M6.5 2a.5.5 0 0 0 0 1h3a.5.5 0 0 0 0-1h-3zM11 8a3 3 0 1 1-6 0 3 3 0 0 1 6 0z&#39;\/%3E%3Cpath d=&#39;M4.5 0A2.5 2.5 0 0 0 2 2.5V14a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V2.5A2.5 2.5 0 0 0 11.5 0h-7zM3 2.5A1.5 1.5 0 0 1 4.5 1h7A1.5 1.5 0 0 1 13 2.5v10.795a4.2 4.2 0 0 0-.776-.492C11.392 12.387 10.063 12 8 12s-3.392.387-4.224.803a4.2 4.2 0 0 0-.776.492V2.5z&#39;\/%3E%3C\/svg%3E&quot;<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6F42C1\">.bi-person-fill-nav-menu<\/span><span style=\"color: #24292E\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #005CC5\">background-image<\/span><span style=\"color: #24292E\">: <\/span><span style=\"color: #005CC5\">url<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #032F62\">&quot;data:image\/svg+xml,%3Csvg xmlns=&#39;http:\/\/www.w3.org\/2000\/svg&#39; width=&#39;16&#39; height=&#39;16&#39; fill=&#39;white&#39; class=&#39;bi bi-person-fill&#39; viewBox=&#39;0 0 16 16&#39;%3E%3Cpath d=&#39;M3 14s-1 0-1-1 1-4 6-4 6 3 6 4-1 1-1 1H3Zm5-6a3 3 0 1 0 0-6 3 3 0 0 0 0 6Z&#39;\/%3E%3C\/svg%3E&quot;<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #6F42C1\">.bi-arrow-bar-left-nav-menu<\/span><span style=\"color: #24292E\"> {<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #005CC5\">background-image<\/span><span style=\"color: #24292E\">: <\/span><span style=\"color: #005CC5\">url<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #032F62\">&quot;data:image\/svg+xml,%3Csvg xmlns=&#39;http:\/\/www.w3.org\/2000\/svg&#39; width=&#39;16&#39; height=&#39;16&#39; fill=&#39;white&#39; class=&#39;bi bi-arrow-bar-left&#39; viewBox=&#39;0 0 16 16&#39;%3E%3Cpath d=&#39;M12.5 15a.5.5 0 0 1-.5-.5v-13a.5.5 0 0 1 1 0v13a.5.5 0 0 1-.5.5ZM10 8a.5.5 0 0 1-.5.5H3.707l2.147 2.146a.5.5 0 0 1-.708.708l-3-3a.5.5 0 0 1 0-.708l3-3a.5.5 0 1 1 .708.708L3.707 7.5H9.5a.5.5 0 0 1 .5.5Z&#39;\/%3E%3C\/svg%3E&quot;<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6F42C1\">.bi-detail-nav-menu<\/span><span style=\"color: #24292E\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #005CC5\">background-image<\/span><span style=\"color: #24292E\">: <\/span><span style=\"color: #005CC5\">url<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #032F62\">&quot;data:image\/svg+xml, %3Csvg xmlns=&#39;http:\/\/www.w3.org\/2000\/svg&#39; width=&#39;16&#39; height=&#39;16&#39; fill=&#39;white&#39; class=&#39;bi bi-card-text&#39; viewBox=&#39;0 0 16 16&#39;%3E %3Cpath d=&#39;M14.5 3a.5.5 0 0 1 .5.5v9a.5.5 0 0 1-.5.5h-13a.5.5 0 0 1-.5-.5v-9a.5.5 0 0 1 .5-.5zm-13-1A1.5 1.5 0 0 0 0 3.5v9A1.5 1.5 0 0 0 1.5 14h13a1.5 1.5 0 0 0 1.5-1.5v-9A1.5 1.5 0 0 0 14.5 2z&#39;\/%3E %3Cpath d=&#39;M3 5.5a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5M3 8a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9A.5.5 0 0 1 3 8m0 2.5a.5.5 0 0 1 .5-.5h6a.5.5 0 0 1 0 1h-6a.5.5 0 0 1-.5-.5&#39;\/%3E %3C\/svg%3E&quot;<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6F42C1\">.nav-item<\/span><span style=\"color: #24292E\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #005CC5\">font-size<\/span><span style=\"color: #24292E\">: <\/span><span style=\"color: #005CC5\">0.9<\/span><span style=\"color: #D73A49\">rem<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #005CC5\">padding-bottom<\/span><span style=\"color: #24292E\">: <\/span><span style=\"color: #005CC5\">0.5<\/span><span style=\"color: #D73A49\">rem<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">...<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Now the app seems to have a better task focus.  Note that the use of <em>AuthorizeView <\/em>in <em>NavMenu.razor<\/em> only controls what is shown in the menu; it does not prevent the user from navigating to the other pages using the browser address bar.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">At this point you can remove <em>Components\/Pages\/Home.razor<\/em> if you wish.  You will need to remove the first <em>NavLink <\/em>section from <em>Components\/Layout\/NavMenu.razor<\/em> and also add  <code>@page \"\/\"<\/code>  to the top of <em>Components\/Pages\/Login.razor<\/em> so that it displays by default when you navigate to the app.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">User Authentication<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The Login page shown previously simply authenticated the user regardless of the username and password supplied.  We will now implement a true server login.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Until now the app works equally well in both the development and deployed environments.  The addition of a username\/password check to the app will complicate matters as the authentication methods for Windows (my development environment) and Linux (my deployment environment) are quite different.  We can hide some of this complexity through the use of Blazor&#8217;s dependency injection mechanism.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Create a generic login handler <em>Authentication\/ServerAuthenticationManager.cs<\/em>:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">C#<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>namespace BlazorSecurityDemo.Authentication\n{\n    public class UserPrivilege(string name, bool isGranted)\n    {\n        public string Name { get; } = name;\n        public bool IsGranted { get; } = isGranted;\n\n        public override string ToString()\n        {\n            return $\"{Name}: {IsGranted}\";\n        }\n    }\n\n    public class UserAuthenticationDetails(string username, bool isAuthenticated, \n        List&lt;string> groups, List&lt;UserPrivilege> privileges)\n    {\n        public string Username { get; } = username;\n        public bool IsAuthenticated { get; } = isAuthenticated;\n        public List&lt;string> Groups { get; } = groups;\n        public List&lt;UserPrivilege> Privileges { get; } = privileges;\n    }\n\n    public abstract class ServerAuthenticationManager\n    {\n        public abstract Task&lt;UserAuthenticationDetails> \n            CheckPasswordAsync(string username, string password);\n    }\n}\n<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D73A49\">namespace<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">BlazorSecurityDemo<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Authentication<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">class<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">UserPrivilege<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">name<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #D73A49\">bool<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">isGranted<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Name<\/span><span style=\"color: #24292E\"> { <\/span><span style=\"color: #D73A49\">get<\/span><span style=\"color: #24292E\">; } <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> name;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">bool<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">IsGranted<\/span><span style=\"color: #24292E\"> { <\/span><span style=\"color: #D73A49\">get<\/span><span style=\"color: #24292E\">; } <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> isGranted;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">override<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">ToString<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">$&quot;{<\/span><span style=\"color: #24292E\">Name<\/span><span style=\"color: #032F62\">}: {<\/span><span style=\"color: #24292E\">IsGranted<\/span><span style=\"color: #032F62\">}&quot;<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">class<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">UserAuthenticationDetails<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">username<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #D73A49\">bool<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">isAuthenticated<\/span><span style=\"color: #24292E\">, <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #6F42C1\">List<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\">&gt; <\/span><span style=\"color: #6F42C1\">groups<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #6F42C1\">List<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #6F42C1\">UserPrivilege<\/span><span style=\"color: #24292E\">&gt; <\/span><span style=\"color: #6F42C1\">privileges<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Username<\/span><span style=\"color: #24292E\"> { <\/span><span style=\"color: #D73A49\">get<\/span><span style=\"color: #24292E\">; } <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> username;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">bool<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">IsAuthenticated<\/span><span style=\"color: #24292E\"> { <\/span><span style=\"color: #D73A49\">get<\/span><span style=\"color: #24292E\">; } <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> isAuthenticated;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">List<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\">&gt; <\/span><span style=\"color: #6F42C1\">Groups<\/span><span style=\"color: #24292E\"> { <\/span><span style=\"color: #D73A49\">get<\/span><span style=\"color: #24292E\">; } <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> groups;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">List<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #6F42C1\">UserPrivilege<\/span><span style=\"color: #24292E\">&gt; <\/span><span style=\"color: #6F42C1\">Privileges<\/span><span style=\"color: #24292E\"> { <\/span><span style=\"color: #D73A49\">get<\/span><span style=\"color: #24292E\">; } <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> privileges;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">abstract<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">class<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">ServerAuthenticationManager<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">abstract<\/span><span style=\"color: #24292E\"> Task&lt;UserAuthenticationDetails&gt; <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">CheckPasswordAsync<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">username<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">password<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span>\n<span class=\"line\"><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Create a Windows-specific login handler <em>Authentication\/WindowsAuthenticationManager.cs<\/em>:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">C#<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>namespace BlazorSecurityDemo.Authentication\n{\n    public class WindowsAuthenticationManager : ServerAuthenticationManager\n    {\n        public override Task&lt;UserAuthenticationDetails> \n            CheckPasswordAsync(string username, string password)\n        {\n            return Task.FromResult(new UserAuthenticationDetails(\n                username, \n                true, \n                &#91;\"BUILTIN\\\\Users\"&#93;, \n                &#91;new(\"SeShutdownPrivilege\", false)&#93;)\n                );\n        }\n    }\n}\n<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D73A49\">namespace<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">BlazorSecurityDemo<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Authentication<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">class<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">WindowsAuthenticationManager<\/span><span style=\"color: #24292E\"> : <\/span><span style=\"color: #6F42C1\">ServerAuthenticationManager<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">override<\/span><span style=\"color: #24292E\"> Task&lt;UserAuthenticationDetails&gt; <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">CheckPasswordAsync<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">username<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">password<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> Task.<\/span><span style=\"color: #6F42C1\">FromResult<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">UserAuthenticationDetails<\/span><span style=\"color: #24292E\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                username, <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #005CC5\">true<\/span><span style=\"color: #24292E\">, <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                &#91;<\/span><span style=\"color: #032F62\">&quot;BUILTIN<\/span><span style=\"color: #005CC5\">\\\\<\/span><span style=\"color: #032F62\">Users&quot;<\/span><span style=\"color: #24292E\">&#93;, <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                &#91;<\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #032F62\">&quot;SeShutdownPrivilege&quot;<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #005CC5\">false<\/span><span style=\"color: #24292E\">)&#93;)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                );<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span>\n<span class=\"line\"><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Create a Linux-specific login handler <em>Authentication\/LinuxAuthenticationManager.cs<\/em>:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">C#<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>namespace BlazorSecurityDemo.Authentication\n{\n    public class LinuxAuthenticationManager : ServerAuthenticationManager\n    {\n        public override Task&lt;UserAuthenticationDetails> \n            CheckPasswordAsync(string username, string password)\n        {\n            return Task.FromResult(new UserAuthenticationDetails(\n                username, \n                true, \n                &#91;\"users\"&#93;, \n                [])\n                );\n        }\n    }\n}\n<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D73A49\">namespace<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">BlazorSecurityDemo<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Authentication<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">class<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">LinuxAuthenticationManager<\/span><span style=\"color: #24292E\"> : <\/span><span style=\"color: #6F42C1\">ServerAuthenticationManager<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">override<\/span><span style=\"color: #24292E\"> Task&lt;UserAuthenticationDetails&gt; <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">CheckPasswordAsync<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">username<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">password<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> Task.<\/span><span style=\"color: #6F42C1\">FromResult<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">UserAuthenticationDetails<\/span><span style=\"color: #24292E\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                username, <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #005CC5\">true<\/span><span style=\"color: #24292E\">, <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                &#91;<\/span><span style=\"color: #032F62\">&quot;users&quot;<\/span><span style=\"color: #24292E\">&#93;, <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                [])<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                );<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span>\n<span class=\"line\"><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">The two concrete authentication managers are just stubs for now. We will get to the details soon.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Register the two managers in <em>Program.cs<\/em>:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-highlight-color:rgba(16, 41, 67, 0.2);line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">C#<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>...\nbuilder.Services.AddScoped&lt;AuthenticationStateProvider, UserAuthenticationStateProvider>();\n\nif (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))\n{\n    builder.Services.AddScoped&lt;ServerAuthenticationManager, WindowsAuthenticationManager>();\n}\nelse if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))\n{\n    builder.Services.AddScoped&lt;ServerAuthenticationManager, LinuxAuthenticationManager>();\n}\n\nvar app = builder.Build();\n...<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D73A49\">..<\/span><span style=\"color: #24292E\">.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">builder.Services.<\/span><span style=\"color: #6F42C1\">AddScoped<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #6F42C1\">AuthenticationStateProvider<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #6F42C1\">UserAuthenticationStateProvider<\/span><span style=\"color: #24292E\">&gt;();<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (RuntimeInformation.<\/span><span style=\"color: #6F42C1\">IsOSPlatform<\/span><span style=\"color: #24292E\">(OSPlatform.Windows))<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">{<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">    builder.Services.<\/span><span style=\"color: #6F42C1\">AddScoped<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #6F42C1\">ServerAuthenticationManager<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #6F42C1\">WindowsAuthenticationManager<\/span><span style=\"color: #24292E\">&gt;();<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">}<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D73A49\">else<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (RuntimeInformation.<\/span><span style=\"color: #6F42C1\">IsOSPlatform<\/span><span style=\"color: #24292E\">(OSPlatform.Linux))<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">{<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">    builder.Services.<\/span><span style=\"color: #6F42C1\">AddScoped<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #6F42C1\">ServerAuthenticationManager<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #6F42C1\">LinuxAuthenticationManager<\/span><span style=\"color: #24292E\">&gt;();<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">app<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> builder.<\/span><span style=\"color: #6F42C1\">Build<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">..<\/span><span style=\"color: #24292E\">.<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">When the app is started the runtime environment is queried to determine which platform the app is running on so that the appropriate concrete manager may be used.  This same approach could be used to create stubs for functions that don&#8217;t function in a non-Linux environment.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Now use the generic manager in <em>Authentication\/UserAuthenticationStateProvider.cs<\/em>:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-highlight-color:rgba(16, 41, 67, 0.2);line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">C#<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>using Microsoft.AspNetCore.Components.Authorization;\nusing System.Security.Claims;\n\nnamespace BlazorSecurityDemo.Authentication\n{\n    public class UserAuthenticationStateProvider(\n        ServerAuthenticationManager serverAuthenticationManager) : AuthenticationStateProvider\n    {\n        private readonly ServerAuthenticationManager serverAuthenticationManager = \n            serverAuthenticationManager;\n        private readonly AuthenticationState authenticationState = new(new ClaimsPrincipal());\n...\n        public async Task&lt;bool> AuthenticateUserPasswordAsync(string username, string password)\n        {\n            \/\/ verify username and password\n            var details = \n                await serverAuthenticationManager.CheckPasswordAsync(username, password);\n            if (!details.IsAuthenticated) return false;\n\n            IList&lt;Claim> claims = &#91;\n                new Claim(ClaimTypes.Name, username),\n                .. details.Groups.ConvertAll(group => new Claim(ClaimTypes.Role, group)),\n                .. details.Privileges.ConvertAll(privilege => new Claim(\n                                                                 privilege.Name, \n                                                                 privilege.IsGranted.ToString(), \n                                                                 ClaimValueTypes.Boolean))\n                &#93;;\n\n            var identity = new ClaimsIdentity(claims, \"AuthenticateUser\");\n            var user = new ClaimsPrincipal(identity);\n\n            NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(user)));\n\n            return true;\n        }\n...<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Microsoft<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">AspNetCore<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Components<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Authorization<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">System<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Security<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Claims<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">namespace<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">BlazorSecurityDemo<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Authentication<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">{<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">class<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">UserAuthenticationStateProvider<\/span><span style=\"color: #24292E\">(<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #6F42C1\">ServerAuthenticationManager<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">serverAuthenticationManager<\/span><span style=\"color: #24292E\">) : <\/span><span style=\"color: #6F42C1\">AuthenticationStateProvider<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    {<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">private<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">readonly<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">ServerAuthenticationManager<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">serverAuthenticationManager<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">            serverAuthenticationManager;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">private<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">readonly<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">AuthenticationState<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">authenticationState<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">ClaimsPrincipal<\/span><span style=\"color: #24292E\">());<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">...<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">async<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Task<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #D73A49\">bool<\/span><span style=\"color: #24292E\">&gt; <\/span><span style=\"color: #6F42C1\">AuthenticateUserPasswordAsync<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">username<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">password<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6A737D\">            \/\/ verify username and password<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">details<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #D73A49\">await<\/span><span style=\"color: #24292E\"> serverAuthenticationManager.<\/span><span style=\"color: #6F42C1\">CheckPasswordAsync<\/span><span style=\"color: #24292E\">(username, password);<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (<\/span><span style=\"color: #D73A49\">!<\/span><span style=\"color: #24292E\">details.IsAuthenticated) <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">false<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">IList<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #6F42C1\">Claim<\/span><span style=\"color: #24292E\">&gt; <\/span><span style=\"color: #6F42C1\">claims<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> &#91;<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Claim<\/span><span style=\"color: #24292E\">(ClaimTypes.Name, username),<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #D73A49\">..<\/span><span style=\"color: #24292E\"> details.Groups.<\/span><span style=\"color: #6F42C1\">ConvertAll<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">group<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Claim<\/span><span style=\"color: #24292E\">(ClaimTypes.Role, group)),<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #D73A49\">..<\/span><span style=\"color: #24292E\"> details.Privileges.<\/span><span style=\"color: #6F42C1\">ConvertAll<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">privilege<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Claim<\/span><span style=\"color: #24292E\">(<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">                                                                 privilege.Name, <\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">                                                                 privilege.IsGranted.<\/span><span style=\"color: #6F42C1\">ToString<\/span><span style=\"color: #24292E\">(), <\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">                                                                 ClaimValueTypes.Boolean))<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #24292E\">                &#93;;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">identity<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">ClaimsIdentity<\/span><span style=\"color: #24292E\">(claims, <\/span><span style=\"color: #032F62\">&quot;AuthenticateUser&quot;<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">user<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">ClaimsPrincipal<\/span><span style=\"color: #24292E\">(identity);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">NotifyAuthenticationStateChanged<\/span><span style=\"color: #24292E\">(Task.<\/span><span style=\"color: #6F42C1\">FromResult<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">AuthenticationState<\/span><span style=\"color: #24292E\">(user)));<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">true<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">...<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The <em>ServerAuthenticationManager <\/em>is injected via the constructor.  When <em>UserAuthenticationStateProvider <\/em>is instantiated at the beginning of an HTTP request scope a concrete implementation of <em>ServerAuthenticationManager <\/em>is injected based on what was registered at app startup &#8211; <em>WindowsAuthenticationManager <\/em>if the app is running on the Windows platform, <em>LinuxAuthenticationManager <\/em>if the app is running on Linux.  If the app is running on a platform that is not Windows or Linux (OSX, for example), this injection will fail as there would be no concrete service registered.  Also note that the injected service must have a lifetime at least as long as consuming service.  In this case, all services are registered as <em>Scoped<\/em>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The <em>UserAuthenticationDetails <\/em>object returned by the <em>CheckPasswordAsync() <\/em>call contains an indication of whether the authentication step succeeded, and also contains lists of what groups and privileges are assigned to the user. The list of groups is converted to a list of <em>Claim<\/em>s of type <em>Role<\/em>, which will prove useful later on. The list of privileges is converted to a list of <em>Claim<\/em>s with the name the same as the privilege and a boolean value based the privilege setting. The <em>Claim<\/em>s are all added to the <em>ClaimsPrincipal <\/em>used for the authentication state for the app.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We will need to validate a username and password on both Windows and Linux and also retrieve group and privilege information.  We could use API calls on both platforms but this will be complicated, especially on Linux where the options for logging in are quite varied.  A simpler approach is to use the command line for both.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Executing commands and retrieving the results from the command line is itself a complex task due to its asynchronous nature and the different output mechanisms for different commands.  Fortunately, I managed to find some code online that I was able to modify to get the job done.  Create <em>Authentication\/CommandProcessor.cs<\/em>:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">C#<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>using System.Diagnostics;\nusing System.Runtime.InteropServices;\nusing System.Security;\n\nnamespace BlazorSecurityDemo.Authentication\n{\n    public static class CommandProcessor\n    {\n        public static Task&lt;int> StartCommand(\n            string command,\n            string? shell = null,\n            string? workingDirectory = null,\n            string? userid = null,\n            string? password = null,\n            int? timeout = null,\n            TextWriter? outputTextWriter = null,\n            TextWriter? errorTextWriter = null)\n        {\n            string escaped = \"\\\"\" + command.Replace(\"\\\"\", \"\\\\\\\"\") + \"\\\"\";\n            string arguments;\n            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))\n            {\n                shell ??= \"cmd.exe\";\n                arguments = \"\/c \" + escaped;\n            }\n            else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))\n            {\n                shell ??= \"\/bin\/sh\";\n                arguments = \"-c \" + escaped;\n            }\n            else\n            {\n                throw new NotImplementedException(\n                    $\"Operating system {RuntimeInformation.OSDescription} not supported\"\n                    );\n            }\n\n            return StartProcess(\n                shell, arguments,\n                workingDirectory: workingDirectory,\n                userid: userid,\n                password: password,\n                timeout: timeout,\n                outputTextWriter: outputTextWriter,\n                errorTextWriter: errorTextWriter\n                );\n        }\n\n        public static async Task&lt;int> StartProcess(\n            string filename,\n            string arguments,\n            string? workingDirectory = null,\n            string? userid = null,\n            string? password = null,\n            int? timeout = null,\n            TextWriter? outputTextWriter = null,\n            TextWriter? errorTextWriter = null)\n        {\n            using var process = new Process()\n            {\n                StartInfo = new ProcessStartInfo()\n                {\n                    CreateNoWindow = true,\n                    Arguments = arguments,\n                    FileName = filename,\n                    RedirectStandardOutput = outputTextWriter != null,\n                    RedirectStandardError = errorTextWriter != null,\n                    UseShellExecute = false,\n                    WorkingDirectory = workingDirectory\n                }\n            };\n\n            if (userid != null &amp;&amp; password != null)\n            {\n                process.StartInfo.UserName = userid;\n\n                SecureString pwd = new();\n                foreach (var ch in password)\n                {\n                    pwd.AppendChar(ch);\n                }\n\n#pragma warning disable CA1416 \/\/ Validate platform compatibility\n                process.StartInfo.Password = pwd;\n#pragma warning restore CA1416 \/\/ Validate platform compatibility\n            }\n\n            var cancellationTokenSource = timeout.HasValue ?\n                new CancellationTokenSource(timeout.Value) :\n                new CancellationTokenSource();\n\n            try\n            {\n                process.Start();\n            }\n            catch (Exception)\n            {\n                return -1;\n            }\n\n            var tasks = new List&lt;Task>(3) {\n                process.WaitForExitAsync(cancellationTokenSource.Token) \n                };\n            if (outputTextWriter != null)\n            {\n                tasks.Add(ReadAsync(\n                    x =>\n                    {\n                        process.OutputDataReceived += x;\n                        process.BeginOutputReadLine();\n                    },\n                    x => process.OutputDataReceived -= x,\n                    outputTextWriter,\n                    cancellationTokenSource.Token));\n            }\n\n            if (errorTextWriter != null)\n            {\n                tasks.Add(ReadAsync(\n                    x =>\n                    {\n                        process.ErrorDataReceived += x;\n                        process.BeginErrorReadLine();\n                    },\n                    x => process.ErrorDataReceived -= x,\n                    errorTextWriter,\n                    cancellationTokenSource.Token));\n            }\n\n            await Task.WhenAll(tasks);\n            return process.ExitCode;\n        }\n\n        public static Task WaitForExitAsync(\n            this Process process,\n            CancellationToken cancellationToken = default)\n        {\n            process.EnableRaisingEvents = true;\n\n            var taskCompletionSource = new TaskCompletionSource&lt;object?>();\n\n            void handler(object? sender, EventArgs args)\n            {\n                process.Exited -= handler;\n                _ = taskCompletionSource.TrySetResult(null);\n            }\n\n            process.Exited += handler;\n\n            if (cancellationToken != default)\n            {\n                cancellationToken.Register(\n                    () =>\n                    {\n                        process.Exited -= handler;\n                        taskCompletionSource.TrySetCanceled();\n                    });\n            }\n\n            return taskCompletionSource.Task;\n        }\n\n        public static Task ReadAsync(\n            this Action&lt;DataReceivedEventHandler> addHandler,\n            Action&lt;DataReceivedEventHandler> removeHandler,\n            TextWriter textWriter,\n            CancellationToken cancellationToken = default)\n        {\n            var taskCompletionSource = new TaskCompletionSource&lt;object?>();\n\n            DataReceivedEventHandler? handler = null;\n            handler = new DataReceivedEventHandler(\n                (sender, e) =>\n                {\n                    if (e.Data == null)\n                    {\n                        if (handler != null)\n                            removeHandler(handler);\n                        taskCompletionSource.TrySetResult(null);\n                    }\n                    else\n                    {\n                        textWriter.WriteLine(e.Data);\n                    }\n                });\n\n            addHandler(handler);\n\n            if (cancellationToken != default)\n            {\n                cancellationToken.Register(\n                    () =>\n                    {\n                        removeHandler(handler);\n                        taskCompletionSource.TrySetCanceled();\n                    });\n            }\n\n            return taskCompletionSource.Task;\n        }\n    }\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">System<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Diagnostics<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">System<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Runtime<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">InteropServices<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">System<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Security<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">namespace<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">BlazorSecurityDemo<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Authentication<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">static<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">class<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">CommandProcessor<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">static<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Task<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #D73A49\">int<\/span><span style=\"color: #24292E\">&gt; <\/span><span style=\"color: #6F42C1\">StartCommand<\/span><span style=\"color: #24292E\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">command<\/span><span style=\"color: #24292E\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\">? <\/span><span style=\"color: #6F42C1\">shell<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">null<\/span><span style=\"color: #24292E\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\">? <\/span><span style=\"color: #6F42C1\">workingDirectory<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">null<\/span><span style=\"color: #24292E\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\">? <\/span><span style=\"color: #6F42C1\">userid<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">null<\/span><span style=\"color: #24292E\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\">? <\/span><span style=\"color: #6F42C1\">password<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">null<\/span><span style=\"color: #24292E\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">int<\/span><span style=\"color: #24292E\">? <\/span><span style=\"color: #6F42C1\">timeout<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">null<\/span><span style=\"color: #24292E\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">TextWriter<\/span><span style=\"color: #24292E\">? <\/span><span style=\"color: #6F42C1\">outputTextWriter<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">null<\/span><span style=\"color: #24292E\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">TextWriter<\/span><span style=\"color: #24292E\">? <\/span><span style=\"color: #6F42C1\">errorTextWriter<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">null<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">escaped<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;<\/span><span style=\"color: #005CC5\">\\&quot;<\/span><span style=\"color: #032F62\">&quot;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">+<\/span><span style=\"color: #24292E\"> command.<\/span><span style=\"color: #6F42C1\">Replace<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #032F62\">&quot;<\/span><span style=\"color: #005CC5\">\\&quot;<\/span><span style=\"color: #032F62\">&quot;<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #032F62\">&quot;<\/span><span style=\"color: #005CC5\">\\\\\\&quot;<\/span><span style=\"color: #032F62\">&quot;<\/span><span style=\"color: #24292E\">) <\/span><span style=\"color: #D73A49\">+<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;<\/span><span style=\"color: #005CC5\">\\&quot;<\/span><span style=\"color: #032F62\">&quot;<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">arguments<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (RuntimeInformation.<\/span><span style=\"color: #6F42C1\">IsOSPlatform<\/span><span style=\"color: #24292E\">(OSPlatform.Windows))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                shell <\/span><span style=\"color: #D73A49\">??=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;cmd.exe&quot;<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                arguments <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;\/c &quot;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">+<\/span><span style=\"color: #24292E\"> escaped;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">else<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (RuntimeInformation.<\/span><span style=\"color: #6F42C1\">IsOSPlatform<\/span><span style=\"color: #24292E\">(OSPlatform.Linux))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                shell <\/span><span style=\"color: #D73A49\">??=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;\/bin\/sh&quot;<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                arguments <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;-c &quot;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">+<\/span><span style=\"color: #24292E\"> escaped;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">else<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #D73A49\">throw<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">NotImplementedException<\/span><span style=\"color: #24292E\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    <\/span><span style=\"color: #032F62\">$&quot;Operating system {<\/span><span style=\"color: #24292E\">RuntimeInformation<\/span><span style=\"color: #032F62\">.<\/span><span style=\"color: #24292E\">OSDescription<\/span><span style=\"color: #032F62\">} not supported&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    );<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">StartProcess<\/span><span style=\"color: #24292E\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                shell, arguments,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #6F42C1\">workingDirectory<\/span><span style=\"color: #24292E\">: workingDirectory,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #6F42C1\">userid<\/span><span style=\"color: #24292E\">: userid,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #6F42C1\">password<\/span><span style=\"color: #24292E\">: password,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #6F42C1\">timeout<\/span><span style=\"color: #24292E\">: timeout,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #6F42C1\">outputTextWriter<\/span><span style=\"color: #24292E\">: outputTextWriter,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #6F42C1\">errorTextWriter<\/span><span style=\"color: #24292E\">: errorTextWriter<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                );<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">static<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">async<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Task<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #D73A49\">int<\/span><span style=\"color: #24292E\">&gt; <\/span><span style=\"color: #6F42C1\">StartProcess<\/span><span style=\"color: #24292E\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">filename<\/span><span style=\"color: #24292E\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">arguments<\/span><span style=\"color: #24292E\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\">? <\/span><span style=\"color: #6F42C1\">workingDirectory<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">null<\/span><span style=\"color: #24292E\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\">? <\/span><span style=\"color: #6F42C1\">userid<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">null<\/span><span style=\"color: #24292E\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\">? <\/span><span style=\"color: #6F42C1\">password<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">null<\/span><span style=\"color: #24292E\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">int<\/span><span style=\"color: #24292E\">? <\/span><span style=\"color: #6F42C1\">timeout<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">null<\/span><span style=\"color: #24292E\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">TextWriter<\/span><span style=\"color: #24292E\">? <\/span><span style=\"color: #6F42C1\">outputTextWriter<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">null<\/span><span style=\"color: #24292E\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">TextWriter<\/span><span style=\"color: #24292E\">? <\/span><span style=\"color: #6F42C1\">errorTextWriter<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">null<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">process<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Process<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                StartInfo <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">ProcessStartInfo<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    CreateNoWindow <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">true<\/span><span style=\"color: #24292E\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    Arguments <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> arguments,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    FileName <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> filename,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    RedirectStandardOutput <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> outputTextWriter <\/span><span style=\"color: #D73A49\">!=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">null<\/span><span style=\"color: #24292E\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    RedirectStandardError <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> errorTextWriter <\/span><span style=\"color: #D73A49\">!=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">null<\/span><span style=\"color: #24292E\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    UseShellExecute <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">false<\/span><span style=\"color: #24292E\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    WorkingDirectory <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> workingDirectory<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            };<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (userid <\/span><span style=\"color: #D73A49\">!=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">null<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">&amp;&amp;<\/span><span style=\"color: #24292E\"> password <\/span><span style=\"color: #D73A49\">!=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">null<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                process.StartInfo.UserName <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> userid;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #6F42C1\">SecureString<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">pwd<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #D73A49\">foreach<\/span><span style=\"color: #24292E\"> (<\/span><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">ch<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">in<\/span><span style=\"color: #24292E\"> password)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    pwd.<\/span><span style=\"color: #6F42C1\">AppendChar<\/span><span style=\"color: #24292E\">(ch);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">#<\/span><span style=\"color: #D73A49\">pragma<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">warning<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">disable<\/span><span style=\"color: #24292E\"> CA1416 <\/span><span style=\"color: #6A737D\">\/\/ Validate platform compatibility<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                process.StartInfo.Password = pwd;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">#<\/span><span style=\"color: #D73A49\">pragma<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">warning<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">restore<\/span><span style=\"color: #24292E\"> CA1416 <\/span><span style=\"color: #6A737D\">\/\/ Validate platform compatibility<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">cancellationTokenSource<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> timeout.HasValue <\/span><span style=\"color: #D73A49\">?<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">CancellationTokenSource<\/span><span style=\"color: #24292E\">(timeout.Value) <\/span><span style=\"color: #D73A49\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">CancellationTokenSource<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">try<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                process.<\/span><span style=\"color: #6F42C1\">Start<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">catch<\/span><span style=\"color: #24292E\"> (<\/span><span style=\"color: #6F42C1\">Exception<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">-<\/span><span style=\"color: #005CC5\">1<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">tasks<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">List<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #6F42C1\">Task<\/span><span style=\"color: #24292E\">&gt;(<\/span><span style=\"color: #005CC5\">3<\/span><span style=\"color: #24292E\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                process.<\/span><span style=\"color: #6F42C1\">WaitForExitAsync<\/span><span style=\"color: #24292E\">(cancellationTokenSource.Token) <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                };<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (outputTextWriter <\/span><span style=\"color: #D73A49\">!=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">null<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                tasks.<\/span><span style=\"color: #6F42C1\">Add<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">ReadAsync<\/span><span style=\"color: #24292E\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    <\/span><span style=\"color: #6F42C1\">x<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                        process.OutputDataReceived <\/span><span style=\"color: #D73A49\">+=<\/span><span style=\"color: #24292E\"> x;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                        process.<\/span><span style=\"color: #6F42C1\">BeginOutputReadLine<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    },<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    <\/span><span style=\"color: #6F42C1\">x<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> process.OutputDataReceived <\/span><span style=\"color: #D73A49\">-=<\/span><span style=\"color: #24292E\"> x,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    outputTextWriter,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    cancellationTokenSource.Token));<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (errorTextWriter <\/span><span style=\"color: #D73A49\">!=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">null<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                tasks.<\/span><span style=\"color: #6F42C1\">Add<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">ReadAsync<\/span><span style=\"color: #24292E\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    <\/span><span style=\"color: #6F42C1\">x<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                        process.ErrorDataReceived <\/span><span style=\"color: #D73A49\">+=<\/span><span style=\"color: #24292E\"> x;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                        process.<\/span><span style=\"color: #6F42C1\">BeginErrorReadLine<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    },<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    <\/span><span style=\"color: #6F42C1\">x<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><span style=\"color: #24292E\"> process.ErrorDataReceived <\/span><span style=\"color: #D73A49\">-=<\/span><span style=\"color: #24292E\"> x,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    errorTextWriter,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    cancellationTokenSource.Token));<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">await<\/span><span style=\"color: #24292E\"> Task.<\/span><span style=\"color: #6F42C1\">WhenAll<\/span><span style=\"color: #24292E\">(tasks);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> process.ExitCode;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        public <\/span><span style=\"color: #D73A49\">static<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Task<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">WaitForExitAsync<\/span><span style=\"color: #24292E\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">this<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Process<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">process<\/span><span style=\"color: #24292E\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">CancellationToken<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">cancellationToken<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">default<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            process.EnableRaisingEvents <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">true<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">taskCompletionSource<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">TaskCompletionSource<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #D73A49\">object<\/span><span style=\"color: #24292E\">?&gt;();<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">void<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">handler<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #D73A49\">object<\/span><span style=\"color: #24292E\">? <\/span><span style=\"color: #6F42C1\">sender<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #6F42C1\">EventArgs<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">args<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                process.Exited <\/span><span style=\"color: #D73A49\">-=<\/span><span style=\"color: #24292E\"> handler;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                _ <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> taskCompletionSource.<\/span><span style=\"color: #6F42C1\">TrySetResult<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #005CC5\">null<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            process.Exited <\/span><span style=\"color: #D73A49\">+=<\/span><span style=\"color: #24292E\"> handler;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (cancellationToken <\/span><span style=\"color: #D73A49\">!=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">default<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                cancellationToken.<\/span><span style=\"color: #6F42C1\">Register<\/span><span style=\"color: #24292E\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    () <\/span><span style=\"color: #D73A49\">=&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                        process.Exited <\/span><span style=\"color: #D73A49\">-=<\/span><span style=\"color: #24292E\"> handler;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                        taskCompletionSource.<\/span><span style=\"color: #6F42C1\">TrySetCanceled<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    });<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> taskCompletionSource.Task;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        public <\/span><span style=\"color: #D73A49\">static<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Task<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">ReadAsync<\/span><span style=\"color: #24292E\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">this<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Action<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #6F42C1\">DataReceivedEventHandler<\/span><span style=\"color: #24292E\">&gt; <\/span><span style=\"color: #6F42C1\">addHandler<\/span><span style=\"color: #24292E\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">Action<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #6F42C1\">DataReceivedEventHandler<\/span><span style=\"color: #24292E\">&gt; <\/span><span style=\"color: #6F42C1\">removeHandler<\/span><span style=\"color: #24292E\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">TextWriter<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">textWriter<\/span><span style=\"color: #24292E\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">CancellationToken<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">cancellationToken<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">default<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">taskCompletionSource<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">TaskCompletionSource<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #D73A49\">object<\/span><span style=\"color: #24292E\">?&gt;();<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">DataReceivedEventHandler<\/span><span style=\"color: #24292E\">? <\/span><span style=\"color: #6F42C1\">handler<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">null<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            handler <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">DataReceivedEventHandler<\/span><span style=\"color: #24292E\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                (<\/span><span style=\"color: #6F42C1\">sender<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #6F42C1\">e<\/span><span style=\"color: #24292E\">) <\/span><span style=\"color: #D73A49\">=&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (e.Data <\/span><span style=\"color: #D73A49\">==<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">null<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                        <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (handler <\/span><span style=\"color: #D73A49\">!=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">null<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                            <\/span><span style=\"color: #6F42C1\">removeHandler<\/span><span style=\"color: #24292E\">(handler);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                        taskCompletionSource.<\/span><span style=\"color: #6F42C1\">TrySetResult<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #005CC5\">null<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    <\/span><span style=\"color: #D73A49\">else<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                        textWriter.<\/span><span style=\"color: #6F42C1\">WriteLine<\/span><span style=\"color: #24292E\">(e.Data);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                });<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">addHandler<\/span><span style=\"color: #24292E\">(handler);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (cancellationToken <\/span><span style=\"color: #D73A49\">!=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">default<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                cancellationToken.<\/span><span style=\"color: #6F42C1\">Register<\/span><span style=\"color: #24292E\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    () <\/span><span style=\"color: #D73A49\">=&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                        <\/span><span style=\"color: #6F42C1\">removeHandler<\/span><span style=\"color: #24292E\">(handler);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                        taskCompletionSource.<\/span><span style=\"color: #6F42C1\">TrySetCanceled<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    });<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> taskCompletionSource.Task;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The userid and password parameters only work on Windows. This does allow us validate the username and password and fetch group and privilege details in one step on that platform. Modify <em>Authentication\/WindowsAuthenticationManager.cs<\/em>:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">C#<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>using System.Text.RegularExpressions;\n\nnamespace BlazorSecurityDemo.Authentication\n{\n    public partial class WindowsAuthenticationManager : ServerAuthenticationManager\n    {\n        public override async Task&lt;UserAuthenticationDetails> \n            CheckPasswordAsync(string username, string password)\n        {\n            using StringWriter sw = new();\n\n            string cmd = \"whoami \/groups \/priv \/fo csv\";\n            var rc = await CommandProcessor.StartCommand(\n                cmd,\n                userid: username,\n                password: password,\n                outputTextWriter: sw\n                );\n            if (rc != 0) return new(username, false, [], []);\n\n            UserAuthenticationDetails result = new(username, true, [], []);\n            ProcessWhoamiOutput(result, sw.ToString());\n\n            return result;\n        }\n\n        private enum InputState\n        {\n            RUNNING, READING_GROUPS, READING_PRIVS\n        };\n\n        private static void ProcessWhoamiOutput(UserAuthenticationDetails response, string output)\n        {\n            var pattern = CSVOutput();\n            var lines = output.Split(\"\\n\");\n            var parseState = InputState.RUNNING;\n            foreach (var line in lines)\n            {\n                var trimmed = line.Trim();\n                switch (parseState)\n                {\n                    case InputState.RUNNING:\n                        if (trimmed.StartsWith(\"\\\"Group Name\"))\n                        {\n                            parseState = InputState.READING_GROUPS;\n                        }\n                        else if (trimmed.StartsWith(\"\\\"Privilege Name\"))\n                        {\n                            parseState = InputState.READING_PRIVS;\n                        }\n                        break;\n                    case InputState.READING_GROUPS:\n                        if (trimmed == \"\")\n                        {\n                            parseState = InputState.RUNNING;\n                            break;\n                        }\n\n                        Match groupMatch = pattern.Match(trimmed);\n                        if (groupMatch.Success)\n                            response.Groups.Add(groupMatch.Groups&#91;\"val\"&#93;.Value);\n                        break;\n                    case InputState.READING_PRIVS:\n                        if (trimmed == \"\")\n                        {\n                            parseState = InputState.RUNNING;\n                            break;\n                        }\n\n                        Match privsMatch = pattern.Match(trimmed);\n                        if (privsMatch.Success)\n                        {\n                            var name = privsMatch.Groups&#91;\"val\"&#93;.Value;\n                            privsMatch = privsMatch.NextMatch();\n                            privsMatch = privsMatch.NextMatch();\n                            var state = privsMatch.Groups&#91;\"val\"&#93;.Value;\n                            response.Privileges.Add(new(name, state == \"Enabled\"));\n                        }\n                        break;\n                    default:\n                        break;\n                }\n            }\n        }\n\n        [GeneratedRegex(@\"\n            # Parse CSV line. Capture next value in named group: 'val'\n            \\s*                      # Ignore leading whitespace.\n            (?:                      # Group of value alternatives.\n              \"\"                     # Either a double quoted string,\n              (?&lt;val>                # Capture contents between quotes.\n                &#91;^\"\"&#93;*(\"\"\"\"&#91;^\"\"&#93;*)*  # Zero or more non-quotes, allowing \n              )                      # doubled \"\" quotes within string.\n              \"\"\\s*                  # Ignore whitespace following quote.\n            |  (?&lt;val>&#91;^,&#93;*)         # Or... zero or more non-commas.\n            )                        # End value alternatives group.\n            (?:,|$)                  # Match end is comma or EOS\", \n            RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace)]\n        private static partial Regex CSVOutput();\n    }\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">System<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Text<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">RegularExpressions<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">namespace<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">BlazorSecurityDemo<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Authentication<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">partial<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">class<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">WindowsAuthenticationManager<\/span><span style=\"color: #24292E\"> : <\/span><span style=\"color: #6F42C1\">ServerAuthenticationManager<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">override<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">async<\/span><span style=\"color: #24292E\"> Task&lt;UserAuthenticationDetails&gt; <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">CheckPasswordAsync<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">username<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">password<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">StringWriter<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">sw<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">cmd<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;whoami \/groups \/priv \/fo csv&quot;<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">rc<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">await<\/span><span style=\"color: #24292E\"> CommandProcessor.<\/span><span style=\"color: #6F42C1\">StartCommand<\/span><span style=\"color: #24292E\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                cmd,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #6F42C1\">userid<\/span><span style=\"color: #24292E\">: username,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #6F42C1\">password<\/span><span style=\"color: #24292E\">: password,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #6F42C1\">outputTextWriter<\/span><span style=\"color: #24292E\">: sw<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                );<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (rc <\/span><span style=\"color: #D73A49\">!=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">0<\/span><span style=\"color: #24292E\">) <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\">(username, <\/span><span style=\"color: #005CC5\">false<\/span><span style=\"color: #24292E\">, [], []);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">UserAuthenticationDetails<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">result<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\">(username, <\/span><span style=\"color: #005CC5\">true<\/span><span style=\"color: #24292E\">, [], []);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">ProcessWhoamiOutput<\/span><span style=\"color: #24292E\">(result, sw.<\/span><span style=\"color: #6F42C1\">ToString<\/span><span style=\"color: #24292E\">());<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> result;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">private<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">enum<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">InputState<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">RUNNING<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #6F42C1\">READING_GROUPS<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #6F42C1\">READING_PRIVS<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        };<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">private<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">static<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">void<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">ProcessWhoamiOutput<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">UserAuthenticationDetails<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">response<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">output<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">pattern<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">CSVOutput<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">lines<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> output.<\/span><span style=\"color: #6F42C1\">Split<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #032F62\">&quot;<\/span><span style=\"color: #005CC5\">\\n<\/span><span style=\"color: #032F62\">&quot;<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">parseState<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> InputState.RUNNING;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">foreach<\/span><span style=\"color: #24292E\"> (<\/span><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">line<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">in<\/span><span style=\"color: #24292E\"> lines)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">trimmed<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> line.<\/span><span style=\"color: #6F42C1\">Trim<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #D73A49\">switch<\/span><span style=\"color: #24292E\"> (parseState)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    <\/span><span style=\"color: #D73A49\">case<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">InputState<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">RUNNING<\/span><span style=\"color: #24292E\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                        <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (trimmed.<\/span><span style=\"color: #6F42C1\">StartsWith<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #032F62\">&quot;<\/span><span style=\"color: #005CC5\">\\&quot;<\/span><span style=\"color: #032F62\">Group Name&quot;<\/span><span style=\"color: #24292E\">))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                            parseState <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> InputState.READING_GROUPS;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                        <\/span><span style=\"color: #D73A49\">else<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (trimmed.<\/span><span style=\"color: #6F42C1\">StartsWith<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #032F62\">&quot;<\/span><span style=\"color: #005CC5\">\\&quot;<\/span><span style=\"color: #032F62\">Privilege Name&quot;<\/span><span style=\"color: #24292E\">))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                            parseState <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> InputState.READING_PRIVS;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                        <\/span><span style=\"color: #D73A49\">break<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    <\/span><span style=\"color: #D73A49\">case<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">InputState<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">READING_GROUPS<\/span><span style=\"color: #24292E\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                        <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (trimmed <\/span><span style=\"color: #D73A49\">==<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;&quot;<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                            parseState <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> InputState.RUNNING;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                            <\/span><span style=\"color: #D73A49\">break<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                        }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                        <\/span><span style=\"color: #6F42C1\">Match<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">groupMatch<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> pattern.<\/span><span style=\"color: #6F42C1\">Match<\/span><span style=\"color: #24292E\">(trimmed);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                        <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (groupMatch.Success)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                            response.Groups.<\/span><span style=\"color: #6F42C1\">Add<\/span><span style=\"color: #24292E\">(groupMatch.Groups&#91;<\/span><span style=\"color: #032F62\">&quot;val&quot;<\/span><span style=\"color: #24292E\">&#93;.Value);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                        <\/span><span style=\"color: #D73A49\">break<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    <\/span><span style=\"color: #D73A49\">case<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">InputState<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">READING_PRIVS<\/span><span style=\"color: #24292E\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                        <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (trimmed <\/span><span style=\"color: #D73A49\">==<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;&quot;<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                            parseState <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> InputState.RUNNING;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                            <\/span><span style=\"color: #D73A49\">break<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                        }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                        <\/span><span style=\"color: #6F42C1\">Match<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">privsMatch<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> pattern.<\/span><span style=\"color: #6F42C1\">Match<\/span><span style=\"color: #24292E\">(trimmed);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                        <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (privsMatch.Success)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                            <\/span><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">name<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> privsMatch.Groups&#91;<\/span><span style=\"color: #032F62\">&quot;val&quot;<\/span><span style=\"color: #24292E\">&#93;.Value;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                            privsMatch <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> privsMatch.<\/span><span style=\"color: #6F42C1\">NextMatch<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                            privsMatch <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> privsMatch.<\/span><span style=\"color: #6F42C1\">NextMatch<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                            <\/span><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">state<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> privsMatch.Groups&#91;<\/span><span style=\"color: #032F62\">&quot;val&quot;<\/span><span style=\"color: #24292E\">&#93;.Value;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                            response.Privileges.<\/span><span style=\"color: #6F42C1\">Add<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\">(name, state <\/span><span style=\"color: #D73A49\">==<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;Enabled&quot;<\/span><span style=\"color: #24292E\">));<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                        <\/span><span style=\"color: #D73A49\">break<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    <\/span><span style=\"color: #D73A49\">default<\/span><span style=\"color: #24292E\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                        <\/span><span style=\"color: #D73A49\">break<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        [<\/span><span style=\"color: #6F42C1\">GeneratedRegex<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #032F62\">@&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #032F62\">            # Parse CSV line. Capture next value in named group: &#39;val&#39;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #032F62\">            \\s*                      # Ignore leading whitespace.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #032F62\">            (?:                      # Group of value alternatives.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #032F62\">              <\/span><span style=\"color: #005CC5\">&quot;&quot;<\/span><span style=\"color: #032F62\">                     # Either a double quoted string,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #032F62\">              (?&lt;val&gt;                # Capture contents between quotes.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #032F62\">                &#91;^<\/span><span style=\"color: #005CC5\">&quot;&quot;<\/span><span style=\"color: #032F62\">&#93;*(<\/span><span style=\"color: #005CC5\">&quot;&quot;&quot;&quot;<\/span><span style=\"color: #032F62\">&#91;^<\/span><span style=\"color: #005CC5\">&quot;&quot;<\/span><span style=\"color: #032F62\">&#93;*)*  # Zero or more non-quotes, allowing <\/span><\/span>\n<span class=\"line\"><span style=\"color: #032F62\">              )                      # doubled <\/span><span style=\"color: #005CC5\">&quot;&quot;<\/span><span style=\"color: #032F62\"> quotes within string.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #032F62\">              <\/span><span style=\"color: #005CC5\">&quot;&quot;<\/span><span style=\"color: #032F62\">\\s*                  # Ignore whitespace following quote.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #032F62\">            |  (?&lt;val&gt;&#91;^,&#93;*)         # Or... zero or more non-commas.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #032F62\">            )                        # End value alternatives group.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #032F62\">            (?:,|$)                  # Match end is comma or EOS&quot;<\/span><span style=\"color: #24292E\">, <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            RegexOptions.Multiline <\/span><span style=\"color: #D73A49\">|<\/span><span style=\"color: #24292E\"> RegexOptions.IgnorePatternWhitespace)]<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">private<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">static<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">partial<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Regex<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">CSVOutput<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The Windows <em>whoami <\/em>command is issued requesting group and privilege information. By setting the userid and password in the <em>StartCommand()<\/em> call we simultaneously verify the password and run the <em>whoami <\/em>command under that userid in order to fetch the information for the correct user. I created a new password-based user account on my development machine to test this in debug mode.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Things are a bit more complicated on Linux, especially if you follow the norm and disable password-based  logins in favour of key files.  As Blazor server apps run as root on Linux by default, we have access to the shadow password file.  This allows us to validate the provided password against what was originally set up for the user.  We can then use the groups command to get the groups for the user.  Linux doesn&#8217;t have a concept of privileges as with Windows, so that list will remain empty.  Modify <em>Authentication\/LinuxAuthenticationManager.cs<\/em>:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">C#<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>namespace BlazorSecurityDemo.Authentication\n{\n    public class LinuxAuthenticationManager : ServerAuthenticationManager\n    {\n        public override async Task&lt;UserAuthenticationDetails> \n            CheckPasswordAsync(string username, string password)\n        {\n            \/\/ validate password against what is in \/etc\/shadow\n\n            using StringWriter shadowsw = new();\n            using StringWriter errorssw = new();\n\n            \/\/ watch out for embedded quote characters\n\n            string cleanedUsername = username.Replace(\"'\", \"\\\\'\");\n            string cleanedPassword = password.Replace(\"'\", \"\\\\'\");\n\n            string cmd = $\"grep '^{cleanedUsername}:' \/etc\/shadow\";\n            var rc = await CommandProcessor.StartCommand(\n                cmd, \n                outputTextWriter: shadowsw, \n                errorTextWriter: errorssw\n                );\n            if (rc != 0)\n            {\n                return new(username, false, [], []);\n            }\n\n            var parts = shadowsw.ToString().Split(':');\n            string encryptedPassword = parts&#91;1&#93;;\n\n            var passwordParts = encryptedPassword.Split(\"$\");\n            if (passwordParts&#91;0&#93;.Length > 0)\n            {\n                return new(username, false, [], []);\n            }\n\n            using StringWriter enchsw = new();\n            if (passwordParts&#91;1&#93; == \"6\")\n            {\n                \/\/ Validate using sha-512\n\n                cmd = $\"mkpasswd -m sha-512 '{cleanedPassword}' '{passwordParts&#91;2&#93;}'\";\n                rc = await CommandProcessor.StartCommand(\n                    cmd, \n                    outputTextWriter: enchsw, \n                    errorTextWriter: errorssw\n                    );\n                if (rc != 0)\n                {\n                    return new(username, false, [], []);\n                }\n            }\n            else if (passwordParts&#91;1&#93; == \"y\")\n            {\n                \/\/ Validate using yescript\n\n                cmd = $\"mkpasswd '{cleanedPassword}' \" + \n                    \"'${passwordParts&#91;1&#93;}${passwordParts&#91;2&#93;}${passwordParts&#91;3&#93;}'\";\n                rc = await CommandProcessor.StartCommand(\n                    cmd, \n                    outputTextWriter: enchsw, \n                    errorTextWriter: errorssw\n                    );\n                if (rc != 0)\n                {\n                    return new(username, false, [], []);\n                }\n            }\n            else\n            {\n                return new(username, false, [], []);\n            }\n\n            string generated = enchsw.ToString();\n            if (generated.Trim() != encryptedPassword.Trim())\n            {\n                return new(username, false, [], []);\n            }\n\n            \/\/ get groups\n\n            UserAuthenticationDetails response = new(username, true, [], []);\n            if (!await GetGroups(response)) return new(username, false, [], []);\n\n            return response;\n        }\n\n        private static async Task&lt;bool> GetGroups(UserAuthenticationDetails response)\n        {\n            using StringWriter groupssw = new();\n            using StringWriter errorssw = new();\n\n            string cleanedUsername = response.Username.Replace(\"'\", \"\\\\'\");\n            string cmd = $\"groups '{cleanedUsername}'\";\n            var rc = await CommandProcessor.StartCommand(\n                cmd, \n                outputTextWriter: groupssw, \n                errorTextWriter: errorssw\n                );\n            if (rc != 0)\n            {\n                return false;\n            }\n\n            var groupList = groupssw.ToString().Split(\" \");\n\n            if (groupList.Length &lt; 3 || groupList&#91;0&#93; != response.Username)\n            {\n                return false;\n            }\n\n            for (int gx = 3; gx &lt; groupList.Length; gx++)\n            {\n                response.Groups.Add(groupList&#91;gx&#93;);\n            }\n\n            return true;\n        }\n    }\n}\n<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D73A49\">namespace<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">BlazorSecurityDemo<\/span><span style=\"color: #24292E\">.<\/span><span style=\"color: #6F42C1\">Authentication<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">class<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">LinuxAuthenticationManager<\/span><span style=\"color: #24292E\"> : <\/span><span style=\"color: #6F42C1\">ServerAuthenticationManager<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">public<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">override<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">async<\/span><span style=\"color: #24292E\"> Task&lt;UserAuthenticationDetails&gt; <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">CheckPasswordAsync<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">username<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">password<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6A737D\">            \/\/ validate password against what is in \/etc\/shadow<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">StringWriter<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">shadowsw<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">StringWriter<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">errorssw<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6A737D\">            \/\/ watch out for embedded quote characters<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">cleanedUsername<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> username.<\/span><span style=\"color: #6F42C1\">Replace<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #032F62\">&quot;&#39;&quot;<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #032F62\">&quot;<\/span><span style=\"color: #005CC5\">\\\\<\/span><span style=\"color: #032F62\">&#39;&quot;<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">cleanedPassword<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> password.<\/span><span style=\"color: #6F42C1\">Replace<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #032F62\">&quot;&#39;&quot;<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #032F62\">&quot;<\/span><span style=\"color: #005CC5\">\\\\<\/span><span style=\"color: #032F62\">&#39;&quot;<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">cmd<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">$&quot;grep &#39;^{<\/span><span style=\"color: #24292E\">cleanedUsername<\/span><span style=\"color: #032F62\">}:&#39; \/etc\/shadow&quot;<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">rc<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">await<\/span><span style=\"color: #24292E\"> CommandProcessor.<\/span><span style=\"color: #6F42C1\">StartCommand<\/span><span style=\"color: #24292E\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                cmd, <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #6F42C1\">outputTextWriter<\/span><span style=\"color: #24292E\">: shadowsw, <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #6F42C1\">errorTextWriter<\/span><span style=\"color: #24292E\">: errorssw<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                );<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (rc <\/span><span style=\"color: #D73A49\">!=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">0<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\">(username, <\/span><span style=\"color: #005CC5\">false<\/span><span style=\"color: #24292E\">, [], []);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">parts<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> shadowsw.<\/span><span style=\"color: #6F42C1\">ToString<\/span><span style=\"color: #24292E\">().<\/span><span style=\"color: #6F42C1\">Split<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #032F62\">&#39;:&#39;<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">encryptedPassword<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> parts&#91;<\/span><span style=\"color: #005CC5\">1<\/span><span style=\"color: #24292E\">&#93;;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">passwordParts<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> encryptedPassword.<\/span><span style=\"color: #6F42C1\">Split<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #032F62\">&quot;$&quot;<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (passwordParts&#91;<\/span><span style=\"color: #005CC5\">0<\/span><span style=\"color: #24292E\">&#93;.Length <\/span><span style=\"color: #D73A49\">&gt;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">0<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\">(username, <\/span><span style=\"color: #005CC5\">false<\/span><span style=\"color: #24292E\">, [], []);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">StringWriter<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">enchsw<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (passwordParts&#91;<\/span><span style=\"color: #005CC5\">1<\/span><span style=\"color: #24292E\">&#93; <\/span><span style=\"color: #D73A49\">==<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;6&quot;<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6A737D\">                \/\/ Validate using sha-512<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                cmd <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">$&quot;mkpasswd -m sha-512 &#39;{<\/span><span style=\"color: #24292E\">cleanedPassword<\/span><span style=\"color: #032F62\">}&#39; &#39;{<\/span><span style=\"color: #24292E\">passwordParts<\/span><span style=\"color: #032F62\">&#91;<\/span><span style=\"color: #005CC5\">2<\/span><span style=\"color: #032F62\">&#93;}&#39;&quot;<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                rc <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">await<\/span><span style=\"color: #24292E\"> CommandProcessor.<\/span><span style=\"color: #6F42C1\">StartCommand<\/span><span style=\"color: #24292E\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    cmd, <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    <\/span><span style=\"color: #6F42C1\">outputTextWriter<\/span><span style=\"color: #24292E\">: enchsw, <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    <\/span><span style=\"color: #6F42C1\">errorTextWriter<\/span><span style=\"color: #24292E\">: errorssw<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    );<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (rc <\/span><span style=\"color: #D73A49\">!=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">0<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\">(username, <\/span><span style=\"color: #005CC5\">false<\/span><span style=\"color: #24292E\">, [], []);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">else<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (passwordParts&#91;<\/span><span style=\"color: #005CC5\">1<\/span><span style=\"color: #24292E\">&#93; <\/span><span style=\"color: #D73A49\">==<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;y&quot;<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6A737D\">                \/\/ Validate using yescript<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                cmd <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">$&quot;mkpasswd &#39;{<\/span><span style=\"color: #24292E\">cleanedPassword<\/span><span style=\"color: #032F62\">}&#39; &quot;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">+<\/span><span style=\"color: #24292E\"> <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    <\/span><span style=\"color: #032F62\">&quot;&#39;${passwordParts&#91;1&#93;}${passwordParts&#91;2&#93;}${passwordParts&#91;3&#93;}&#39;&quot;<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                rc <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">await<\/span><span style=\"color: #24292E\"> CommandProcessor.<\/span><span style=\"color: #6F42C1\">StartCommand<\/span><span style=\"color: #24292E\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    cmd, <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    <\/span><span style=\"color: #6F42C1\">outputTextWriter<\/span><span style=\"color: #24292E\">: enchsw, <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    <\/span><span style=\"color: #6F42C1\">errorTextWriter<\/span><span style=\"color: #24292E\">: errorssw<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    );<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (rc <\/span><span style=\"color: #D73A49\">!=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">0<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                    <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\">(username, <\/span><span style=\"color: #005CC5\">false<\/span><span style=\"color: #24292E\">, [], []);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">else<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\">(username, <\/span><span style=\"color: #005CC5\">false<\/span><span style=\"color: #24292E\">, [], []);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">generated<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> enchsw.<\/span><span style=\"color: #6F42C1\">ToString<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (generated.<\/span><span style=\"color: #6F42C1\">Trim<\/span><span style=\"color: #24292E\">() <\/span><span style=\"color: #D73A49\">!=<\/span><span style=\"color: #24292E\"> encryptedPassword.<\/span><span style=\"color: #6F42C1\">Trim<\/span><span style=\"color: #24292E\">())<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\">(username, <\/span><span style=\"color: #005CC5\">false<\/span><span style=\"color: #24292E\">, [], []);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6A737D\">            \/\/ get groups<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #6F42C1\">UserAuthenticationDetails<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">response<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\">(username, <\/span><span style=\"color: #005CC5\">true<\/span><span style=\"color: #24292E\">, [], []);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (<\/span><span style=\"color: #D73A49\">!await<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">GetGroups<\/span><span style=\"color: #24292E\">(response)) <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\">(username, <\/span><span style=\"color: #005CC5\">false<\/span><span style=\"color: #24292E\">, [], []);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> response;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">private<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">static<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">async<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Task<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #D73A49\">bool<\/span><span style=\"color: #24292E\">&gt; <\/span><span style=\"color: #6F42C1\">GetGroups<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #6F42C1\">UserAuthenticationDetails<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">response<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">StringWriter<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">groupssw<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">using<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">StringWriter<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">errorssw<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">new<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">cleanedUsername<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> response.Username.<\/span><span style=\"color: #6F42C1\">Replace<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #032F62\">&quot;&#39;&quot;<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #032F62\">&quot;<\/span><span style=\"color: #005CC5\">\\\\<\/span><span style=\"color: #032F62\">&#39;&quot;<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">cmd<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">$&quot;groups &#39;{<\/span><span style=\"color: #24292E\">cleanedUsername<\/span><span style=\"color: #032F62\">}&#39;&quot;<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">rc<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">await<\/span><span style=\"color: #24292E\"> CommandProcessor.<\/span><span style=\"color: #6F42C1\">StartCommand<\/span><span style=\"color: #24292E\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                cmd, <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #6F42C1\">outputTextWriter<\/span><span style=\"color: #24292E\">: groupssw, <\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #6F42C1\">errorTextWriter<\/span><span style=\"color: #24292E\">: errorssw<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                );<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (rc <\/span><span style=\"color: #D73A49\">!=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">0<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">false<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">groupList<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> groupssw.<\/span><span style=\"color: #6F42C1\">ToString<\/span><span style=\"color: #24292E\">().<\/span><span style=\"color: #6F42C1\">Split<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #032F62\">&quot; &quot;<\/span><span style=\"color: #24292E\">);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> (groupList.Length <\/span><span style=\"color: #D73A49\">&lt;<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">3<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">||<\/span><span style=\"color: #24292E\"> groupList&#91;<\/span><span style=\"color: #005CC5\">0<\/span><span style=\"color: #24292E\">&#93; <\/span><span style=\"color: #D73A49\">!=<\/span><span style=\"color: #24292E\"> response.Username)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">false<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">for<\/span><span style=\"color: #24292E\"> (<\/span><span style=\"color: #D73A49\">int<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">gx<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">3<\/span><span style=\"color: #24292E\">; gx <\/span><span style=\"color: #D73A49\">&lt;<\/span><span style=\"color: #24292E\"> groupList.Length; gx<\/span><span style=\"color: #D73A49\">++<\/span><span style=\"color: #24292E\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">                response.Groups.<\/span><span style=\"color: #6F42C1\">Add<\/span><span style=\"color: #24292E\">(groupList&#91;gx&#93;);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            <\/span><span style=\"color: #D73A49\">return<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #005CC5\">true<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">}<\/span><\/span>\n<span class=\"line\"><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Depending on applied updates a Ubuntu 22.04.1 distribution will be using either <em>sha-512<\/em> or <em>yescript <\/em>for password encryption. There will be an indicator at the beginning of the encrypted password string of which encryption method is used. You may need to install the <em>whois <\/em>package on your Linux system to get the <em>mkpasswd <\/em>command. You should try these commands from the Linux command line to familiarize yourself with the output and to check that they are supported.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We now have a way to validate a username and password and get the list of groups for the user, and for Windows, the list of privileges. We can test for the appropriate <em>Claim<\/em>s when performing various tasks to ensure that the user would be able to accomplish these tasks when using the command line. Coding for the different possible <em>Claim<\/em>s for the <em>ClaimsPrincipal<\/em> is cumbersome. A better way to handle this is to use <em>policies<\/em>. Add the following to <em>Program.cs<\/em>:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">C#<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>...\n\/\/ Add policies\nbuilder.Services.AddAuthorizationBuilder().AddPolicy(\"admin\", policy =>\n{\n    \/\/ either Windows admin or Linux sudoer\n    policy.RequireRole(&#91;\"BUILTIN\\\\Administrators\", \"sudo\"&#93;);\n});\n\nvar app = builder.Build();\n...\n<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D73A49\">..<\/span><span style=\"color: #24292E\">.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6A737D\">\/\/ Add policies<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">builder.Services.<\/span><span style=\"color: #6F42C1\">AddAuthorizationBuilder<\/span><span style=\"color: #24292E\">().<\/span><span style=\"color: #6F42C1\">AddPolicy<\/span><span style=\"color: #24292E\">(<\/span><span style=\"color: #032F62\">&quot;admin&quot;<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #6F42C1\">policy<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6A737D\">    \/\/ either Windows admin or Linux sudoer<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    policy.<\/span><span style=\"color: #6F42C1\">RequireRole<\/span><span style=\"color: #24292E\">(&#91;<\/span><span style=\"color: #032F62\">&quot;BUILTIN<\/span><span style=\"color: #005CC5\">\\\\<\/span><span style=\"color: #032F62\">Administrators&quot;<\/span><span style=\"color: #24292E\">, <\/span><span style=\"color: #032F62\">&quot;sudo&quot;<\/span><span style=\"color: #24292E\">&#93;);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">});<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">app<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> builder.<\/span><span style=\"color: #6F42C1\">Build<\/span><span style=\"color: #24292E\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">..<\/span><span style=\"color: #24292E\">.<\/span><\/span>\n<span class=\"line\"><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Since we mapped user groups to roles in <em>UserAuthenticationManager <\/em>earlier, we can use <em>RequireRole <\/em>to quickly set up policies.  We can now use this policy to control what is displayed.  Modify <em>Components\/Pages\/UserDetails.razor<\/em>:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(14px, .875rem, 21px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#f2f2f2;color:#2f363c\">Razor<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#24292e;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>...\n&lt;AuthorizeView Policy=\"admin\">\n    &lt;label>Admin thing @actionMessage&lt;\/label>\n    &lt;br \/>\n    &lt;button @onclick=DoAdminThing>Do admin thing&lt;\/button>\n&lt;\/AuthorizeView>\n\n@code {\n    private string actionMessage = \"is not done\";\n\n    &#91;Inject&#93;\n    private IAuthorizationService authorizationService { get; set; } = default!;\n\n    &#91;CascadingParameter&#93;\n    private Task&lt;AuthenticationState> authenticationStateTask { get; set; } = default!;\n\n    private async Task DoAdminThing()\n    {\n        var user = (await authenticationStateTask).User;\n        if ((await authorizationService.AuthorizeAsync(user, \"admin\")).Succeeded)\n        {\n            actionMessage = \"is done\";\n        }\n        else\n        {\n            actionMessage = $\"cannot be done by {user.Identity?.Name}\";\n        }\n\n    }\n}\n<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki github-light\" style=\"background-color: #fff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #24292E\">...<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #B31D28; font-style: italic\">AuthorizeView<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Policy<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">&quot;admin&quot;<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    &lt;<\/span><span style=\"color: #22863A\">label<\/span><span style=\"color: #24292E\">&gt;Admin thing <\/span><span style=\"color: #D73A49\">@<\/span><span style=\"color: #24292E\">actionMessage&lt;\/<\/span><span style=\"color: #22863A\">label<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    &lt;<\/span><span style=\"color: #22863A\">br<\/span><span style=\"color: #24292E\"> \/&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    &lt;<\/span><span style=\"color: #22863A\">button<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">@onclick<\/span><span style=\"color: #24292E\">=<\/span><span style=\"color: #032F62\">DoAdminThing<\/span><span style=\"color: #24292E\">&gt;Do admin thing&lt;\/<\/span><span style=\"color: #22863A\">button<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">&lt;\/<\/span><span style=\"color: #B31D28; font-style: italic\">AuthorizeView<\/span><span style=\"color: #24292E\">&gt;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">@code<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">private<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">string<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">actionMessage<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;is not done&quot;<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    &#91;<\/span><span style=\"color: #6F42C1\">Inject<\/span><span style=\"color: #24292E\">&#93;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">private<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">IAuthorizationService<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">authorizationService<\/span><span style=\"color: #24292E\"> { <\/span><span style=\"color: #D73A49\">get<\/span><span style=\"color: #24292E\">; <\/span><span style=\"color: #D73A49\">set<\/span><span style=\"color: #24292E\">; } <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">default!<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    &#91;<\/span><span style=\"color: #6F42C1\">CascadingParameter<\/span><span style=\"color: #24292E\">&#93;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">private<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Task<\/span><span style=\"color: #24292E\">&lt;<\/span><span style=\"color: #6F42C1\">AuthenticationState<\/span><span style=\"color: #24292E\">&gt; <\/span><span style=\"color: #6F42C1\">authenticationStateTask<\/span><span style=\"color: #24292E\"> { <\/span><span style=\"color: #D73A49\">get<\/span><span style=\"color: #24292E\">; <\/span><span style=\"color: #D73A49\">set<\/span><span style=\"color: #24292E\">; } <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">default!<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    <\/span><span style=\"color: #D73A49\">private<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">async<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">Task<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">DoAdminThing<\/span><span style=\"color: #24292E\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">var<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #6F42C1\">user<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> (<\/span><span style=\"color: #D73A49\">await<\/span><span style=\"color: #24292E\"> authenticationStateTask).User;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">if<\/span><span style=\"color: #24292E\"> ((<\/span><span style=\"color: #D73A49\">await<\/span><span style=\"color: #24292E\"> authorizationService.<\/span><span style=\"color: #6F42C1\">AuthorizeAsync<\/span><span style=\"color: #24292E\">(user, <\/span><span style=\"color: #032F62\">&quot;admin&quot;<\/span><span style=\"color: #24292E\">)).Succeeded)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            actionMessage <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">&quot;is done&quot;<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        <\/span><span style=\"color: #D73A49\">else<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">            actionMessage <\/span><span style=\"color: #D73A49\">=<\/span><span style=\"color: #24292E\"> <\/span><span style=\"color: #032F62\">$&quot;cannot be done by {<\/span><span style=\"color: #24292E\">user<\/span><span style=\"color: #032F62\">.<\/span><span style=\"color: #24292E\">Identity<\/span><span style=\"color: #D73A49\">?<\/span><span style=\"color: #032F62\">.<\/span><span style=\"color: #24292E\">Name<\/span><span style=\"color: #032F62\">}&quot;<\/span><span style=\"color: #24292E\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">        }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #24292E\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D73A49\">}<\/span><\/span>\n<span class=\"line\"><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Please note that <em>AuthorizeView <\/em>only controls what is displayed on the page. To actually verify that the user does satisfy the policy, use the <em>AuthorizeAsync <\/em>method in a function that needs heightened authority, or check the authorization in an API method. This way if the admin action button is accidently exposed to a non-authorized user via a page edit, the function is still protected.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">This post presented a simple approach for securing a web application.  As application security is a complex subject you should carefully consider your requirements when designing a solution.  Hopefully the concepts presented here will help you on your way.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A simple approach for securing a Blazor web application is presented.  Authentication for both Windows and Linux is shown.<\/p>\n","protected":false},"author":1,"featured_media":103,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_themeisle_gutenberg_block_has_review":false,"footnotes":""},"categories":[10],"tags":[11,13,16],"class_list":["post-165","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-development","tag-blazor","tag-linux","tag-security"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/lcigaming.ca\/articles\/wp-json\/wp\/v2\/posts\/165","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/lcigaming.ca\/articles\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/lcigaming.ca\/articles\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/lcigaming.ca\/articles\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/lcigaming.ca\/articles\/wp-json\/wp\/v2\/comments?post=165"}],"version-history":[{"count":3,"href":"https:\/\/lcigaming.ca\/articles\/wp-json\/wp\/v2\/posts\/165\/revisions"}],"predecessor-version":[{"id":177,"href":"https:\/\/lcigaming.ca\/articles\/wp-json\/wp\/v2\/posts\/165\/revisions\/177"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/lcigaming.ca\/articles\/wp-json\/wp\/v2\/media\/103"}],"wp:attachment":[{"href":"https:\/\/lcigaming.ca\/articles\/wp-json\/wp\/v2\/media?parent=165"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/lcigaming.ca\/articles\/wp-json\/wp\/v2\/categories?post=165"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/lcigaming.ca\/articles\/wp-json\/wp\/v2\/tags?post=165"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}