{"id":1921,"date":"2024-06-17T22:39:09","date_gmt":"2024-06-17T22:39:09","guid":{"rendered":"https:\/\/www.w3computing.com\/articles\/?p=1921"},"modified":"2024-06-17T22:39:15","modified_gmt":"2024-06-17T22:39:15","slug":"building-secure-single-page-applications-spas-with-csharp-and-blazor","status":"publish","type":"post","link":"https:\/\/www.w3computing.com\/articles\/building-secure-single-page-applications-spas-with-csharp-and-blazor\/","title":{"rendered":"Building Secure Single Page Applications (SPAs) with C# and Blazor"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">Introduction<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">In web development, Single Page Applications (SPAs) have gained immense popularity due to their seamless user experience and enhanced performance. SPAs load a single HTML page and dynamically update content as the user interacts with the application. However, with the increasing complexity of SPAs, ensuring security has become a paramount concern.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This tutorial will guide you through building a secure SPA using C# and Blazor, Microsoft&#8217;s open-source framework for creating interactive web UIs with .NET. We will cover key security aspects such as authentication, authorization, data protection, and secure communication. This tutorial is intended for developers who have a basic understanding of Blazor and .NET but are looking to deepen their knowledge in securing SPAs.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Prerequisites<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Before we start, make sure you have the following tools and knowledge:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Visual Studio 2019\/2022<\/strong>: You can download it from <a href=\"https:\/\/visualstudio.microsoft.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">Visual Studio&#8217;s official website<\/a>.<\/li>\n\n\n\n<li><strong>.NET 5 or later<\/strong>: Ensure you have the latest version installed. Download from <a href=\"https:\/\/dotnet.microsoft.com\/download\/dotnet\/5.0\" target=\"_blank\" rel=\"noreferrer noopener\">here<\/a>.<\/li>\n\n\n\n<li><strong>Basic understanding of Blazor<\/strong>: Familiarity with creating Blazor components and basic routing.<\/li>\n\n\n\n<li><strong>Knowledge of C#<\/strong>: Understanding of C# programming language.<\/li>\n\n\n\n<li><strong>Basic understanding of web security concepts<\/strong>: Familiarity with terms like authentication, authorization, CSRF, XSS, etc.<\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\">Setting Up the Project<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Step 1: Create a Blazor WebAssembly Project<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Open Visual Studio and create a new project. Select &#8220;Blazor WebAssembly App&#8221; and click &#8220;Next.&#8221; Name your project &#8220;SecureBlazorSPA&#8221; and choose a location to save it. Ensure the &#8220;ASP.NET Core hosted&#8221; checkbox is selected. This setting creates a solution with three projects: a Blazor WebAssembly project, an ASP.NET Core server project, and a shared project for shared code.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Step 2: Configure HTTPS<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">To ensure secure communication, make sure your application uses HTTPS. Visual Studio sets this up by default, but it&#8217;s good to verify.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Open the <code>launchSettings.json<\/code> file in the <code>Server<\/code> project.<\/li>\n\n\n\n<li>Ensure the <code>https<\/code> profile is configured correctly. It should look something like this:<\/li>\n<\/ol>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"JSON \/ JSON with Comments\" data-shcb-language-slug=\"json\"><span><code class=\"hljs language-json\"><span class=\"hljs-string\">\"profiles\"<\/span>: {\n    <span class=\"hljs-attr\">\"https\"<\/span>: {\n        <span class=\"hljs-attr\">\"commandName\"<\/span>: <span class=\"hljs-string\">\"Project\"<\/span>,\n        <span class=\"hljs-attr\">\"dotnetRunMessages\"<\/span>: <span class=\"hljs-literal\">true<\/span>,\n        <span class=\"hljs-attr\">\"launchBrowser\"<\/span>: <span class=\"hljs-literal\">true<\/span>,\n        <span class=\"hljs-attr\">\"applicationUrl\"<\/span>: <span class=\"hljs-string\">\"https:\/\/localhost:5001;http:\/\/localhost:5000\"<\/span>,\n        <span class=\"hljs-attr\">\"environmentVariables\"<\/span>: {\n            <span class=\"hljs-attr\">\"ASPNETCORE_ENVIRONMENT\"<\/span>: <span class=\"hljs-string\">\"Development\"<\/span>\n        }\n    }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JSON \/ JSON with Comments<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">json<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">Step 3: Configure Authentication and Authorization<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">For this tutorial, we&#8217;ll use ASP.NET Core Identity for authentication and authorization. ASP.NET Core Identity provides a framework for managing user accounts, roles, and more.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Install the Required NuGet Packages<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">In the <code>Server<\/code> project, install the following NuGet packages:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\">dotnet <span class=\"hljs-keyword\">add<\/span> package Microsoft.AspNetCore.Identity.EntityFrameworkCore\ndotnet <span class=\"hljs-keyword\">add<\/span> package Microsoft.AspNetCore.Authentication.JwtBearer\ndotnet <span class=\"hljs-keyword\">add<\/span> package Microsoft.IdentityModel.Tokens\ndotnet <span class=\"hljs-keyword\">add<\/span> package System.IdentityModel.Tokens.Jwt<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h4 class=\"wp-block-heading\">Set Up Identity<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Open <code>Startup.cs<\/code> in the <code>Server<\/code> project and add the following using statements:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-keyword\">using<\/span> Microsoft.AspNetCore.Authentication.JwtBearer;\n<span class=\"hljs-keyword\">using<\/span> Microsoft.AspNetCore.Identity;\n<span class=\"hljs-keyword\">using<\/span> Microsoft.EntityFrameworkCore;\n<span class=\"hljs-keyword\">using<\/span> Microsoft.IdentityModel.Tokens;\n<span class=\"hljs-keyword\">using<\/span> SecureBlazorSPA.Server.Data;\n<span class=\"hljs-keyword\">using<\/span> SecureBlazorSPA.Server.Models;\n<span class=\"hljs-keyword\">using<\/span> System.Text;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Configure services in the <code>ConfigureServices<\/code> method:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">ConfigureServices<\/span>(<span class=\"hljs-params\">IServiceCollection services<\/span>)<\/span>\n{\n    services.AddDbContext&lt;ApplicationDbContext&gt;(options =&gt;\n        options.UseSqlServer(Configuration.GetConnectionString(<span class=\"hljs-string\">\"DefaultConnection\"<\/span>)));\n\n    services.AddDefaultIdentity&lt;ApplicationUser&gt;(options =&gt; options.SignIn.RequireConfirmedAccount = <span class=\"hljs-literal\">true<\/span>)\n        .AddRoles&lt;IdentityRole&gt;()\n        .AddEntityFrameworkStores&lt;ApplicationDbContext&gt;();\n\n    services.AddAuthentication(options =&gt;\n    {\n        options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;\n        options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;\n    })\n    .AddJwtBearer(options =&gt;\n    {\n        options.TokenValidationParameters = <span class=\"hljs-keyword\">new<\/span> TokenValidationParameters\n        {\n            ValidateIssuer = <span class=\"hljs-literal\">true<\/span>,\n            ValidateAudience = <span class=\"hljs-literal\">true<\/span>,\n            ValidateLifetime = <span class=\"hljs-literal\">true<\/span>,\n            ValidateIssuerSigningKey = <span class=\"hljs-literal\">true<\/span>,\n            ValidIssuer = Configuration&#91;<span class=\"hljs-string\">\"Jwt:Issuer\"<\/span>],\n            ValidAudience = Configuration&#91;<span class=\"hljs-string\">\"Jwt:Issuer\"<\/span>],\n            IssuerSigningKey = <span class=\"hljs-keyword\">new<\/span> SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration&#91;<span class=\"hljs-string\">\"Jwt:Key\"<\/span>]))\n        };\n    });\n\n    services.AddControllersWithViews();\n    services.AddRazorPages();\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">In the <code>Configure<\/code> method, ensure you add authentication and authorization middleware:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">Configure<\/span>(<span class=\"hljs-params\">IApplicationBuilder app, IWebHostEnvironment env<\/span>)<\/span>\n{\n    <span class=\"hljs-keyword\">if<\/span> (env.IsDevelopment())\n    {\n        app.UseDeveloperExceptionPage();\n        app.UseWebAssemblyDebugging();\n    }\n    <span class=\"hljs-keyword\">else<\/span>\n    {\n        app.UseExceptionHandler(<span class=\"hljs-string\">\"\/Error\"<\/span>);\n        app.UseHsts();\n    }\n\n    app.UseHttpsRedirection();\n    app.UseBlazorFrameworkFiles();\n    app.UseStaticFiles();\n\n    app.UseRouting();\n\n    app.UseAuthentication();\n    app.UseAuthorization();\n\n    app.UseEndpoints(endpoints =&gt;\n    {\n        endpoints.MapRazorPages();\n        endpoints.MapControllers();\n        endpoints.MapFallbackToFile(<span class=\"hljs-string\">\"index.html\"<\/span>);\n    });\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Add JWT settings to your <code>appsettings.json<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"JSON \/ JSON with Comments\" data-shcb-language-slug=\"json\"><span><code class=\"hljs language-json\"><span class=\"hljs-string\">\"Jwt\"<\/span>: {\n    <span class=\"hljs-attr\">\"Key\"<\/span>: <span class=\"hljs-string\">\"YourSecretKey12345678\"<\/span>,\n    <span class=\"hljs-attr\">\"Issuer\"<\/span>: <span class=\"hljs-string\">\"https:\/\/localhost:5001\"<\/span>\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JSON \/ JSON with Comments<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">json<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h4 class=\"wp-block-heading\">Create the Identity Models<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">In the <code>Server<\/code> project, create a <code>Models<\/code> folder.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Create a class <code>ApplicationUser.cs<\/code> that extends <code>IdentityUser<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-keyword\">using<\/span> Microsoft.AspNetCore.Identity;\n\n<span class=\"hljs-keyword\">namespace<\/span> <span class=\"hljs-title\">SecureBlazorSPA.Server.Models<\/span>\n{\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">ApplicationUser<\/span> : <span class=\"hljs-title\">IdentityUser<\/span>\n    {\n    }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Create a <code>Data<\/code> folder and add <code>ApplicationDbContext.cs<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-keyword\">using<\/span> Microsoft.AspNetCore.Identity.EntityFrameworkCore;\n<span class=\"hljs-keyword\">using<\/span> Microsoft.EntityFrameworkCore;\n<span class=\"hljs-keyword\">using<\/span> SecureBlazorSPA.Server.Models;\n\n<span class=\"hljs-keyword\">namespace<\/span> <span class=\"hljs-title\">SecureBlazorSPA.Server.Data<\/span>\n{\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">ApplicationDbContext<\/span> : <span class=\"hljs-title\">IdentityDbContext<\/span>&lt;<span class=\"hljs-title\">ApplicationUser<\/span>&gt;\n    {\n        <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-title\">ApplicationDbContext<\/span>(<span class=\"hljs-params\">DbContextOptions&lt;ApplicationDbContext&gt; options<\/span>)\n            : <span class=\"hljs-title\">base<\/span>(<span class=\"hljs-params\">options<\/span>)<\/span>\n        {\n        }\n    }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Update the <code>ApplicationDbContext<\/code> in <code>Startup.cs<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\">services.AddDbContext&lt;ApplicationDbContext&gt;(options =&gt;\n    options.UseSqlServer(Configuration.GetConnectionString(<span class=\"hljs-string\">\"DefaultConnection\"<\/span>)));<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Update <code>appsettings.json<\/code> with your connection string:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"JSON \/ JSON with Comments\" data-shcb-language-slug=\"json\"><span><code class=\"hljs language-json\"><span class=\"hljs-string\">\"ConnectionStrings\"<\/span>: {\n    <span class=\"hljs-attr\">\"DefaultConnection\"<\/span>: <span class=\"hljs-string\">\"Server=(localdb)\\\\mssqllocaldb;Database=aspnet-SecureBlazorSPA;Trusted_Connection=True;MultipleActiveResultSets=true\"<\/span>\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JSON \/ JSON with Comments<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">json<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Run the following commands to create and apply the initial migration:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"Bash\" data-shcb-language-slug=\"bash\"><span><code class=\"hljs language-bash\">dotnet ef migrations add InitialCreate --project SecureBlazorSPA.Server\ndotnet ef database update --project SecureBlazorSPA.Server<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">Bash<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">bash<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">Step 4: Create a Token Service<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">In the <code>Server<\/code> project, create a <code>Services<\/code> folder and add <code>ITokenService.cs<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-keyword\">using<\/span> System.Threading.Tasks;\n\n<span class=\"hljs-keyword\">namespace<\/span> <span class=\"hljs-title\">SecureBlazorSPA.Server.Services<\/span>\n{\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">interface<\/span> <span class=\"hljs-title\">ITokenService<\/span>\n    {\n        <span class=\"hljs-function\">Task&lt;<span class=\"hljs-keyword\">string<\/span>&gt; <span class=\"hljs-title\">GenerateToken<\/span>(<span class=\"hljs-params\">ApplicationUser user<\/span>)<\/span>;\n    }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Implement the interface in <code>TokenService.cs<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-keyword\">using<\/span> Microsoft.Extensions.Configuration;\n<span class=\"hljs-keyword\">using<\/span> Microsoft.IdentityModel.Tokens;\n<span class=\"hljs-keyword\">using<\/span> SecureBlazorSPA.Server.Models;\n<span class=\"hljs-keyword\">using<\/span> System;\n<span class=\"hljs-keyword\">using<\/span> System.IdentityModel.Tokens.Jwt;\n<span class=\"hljs-keyword\">using<\/span> System.Security.Claims;\n<span class=\"hljs-keyword\">using<\/span> System.Text;\n<span class=\"hljs-keyword\">using<\/span> System.Threading.Tasks;\n\n<span class=\"hljs-keyword\">namespace<\/span> <span class=\"hljs-title\">SecureBlazorSPA.Server.Services<\/span>\n{\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">TokenService<\/span> : <span class=\"hljs-title\">ITokenService<\/span>\n    {\n        <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">readonly<\/span> IConfiguration _configuration;\n\n        <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-title\">TokenService<\/span>(<span class=\"hljs-params\">IConfiguration configuration<\/span>)<\/span>\n        {\n            _configuration = configuration;\n        }\n\n        <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">async<\/span> Task&lt;<span class=\"hljs-keyword\">string<\/span>&gt; <span class=\"hljs-title\">GenerateToken<\/span>(<span class=\"hljs-params\">ApplicationUser user<\/span>)<\/span>\n        {\n            <span class=\"hljs-keyword\">var<\/span> claims = <span class=\"hljs-keyword\">new<\/span>&#91;]\n            {\n                <span class=\"hljs-keyword\">new<\/span> Claim(JwtRegisteredClaimNames.Sub, user.UserName),\n                <span class=\"hljs-keyword\">new<\/span> Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())\n            };\n\n            <span class=\"hljs-keyword\">var<\/span> key = <span class=\"hljs-keyword\">new<\/span> SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration&#91;<span class=\"hljs-string\">\"Jwt:Key\"<\/span>]));\n            <span class=\"hljs-keyword\">var<\/span> creds = <span class=\"hljs-keyword\">new<\/span> SigningCredentials(key, SecurityAlgorithms.HmacSha256);\n\n            <span class=\"hljs-keyword\">var<\/span> token = <span class=\"hljs-keyword\">new<\/span> JwtSecurityToken(\n                issuer: _configuration&#91;<span class=\"hljs-string\">\"Jwt:Issuer\"<\/span>],\n                audience: _configuration&#91;<span class=\"hljs-string\">\"Jwt:Issuer\"<\/span>],\n                claims: claims,\n                expires: DateTime.Now.AddMinutes(<span class=\"hljs-number\">30<\/span>),\n                signingCredentials: creds);\n\n            <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-keyword\">new<\/span> JwtSecurityTokenHandler().WriteToken(token);\n        }\n    }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Register the <code>TokenService<\/code> in <code>Startup.cs<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-14\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\">services.AddTransient&lt;ITokenService, TokenService&gt;();<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-14\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">Step 5: Create Account Controllers<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Create an <code>AccountController<\/code> in the <code>Controllers<\/code> folder of the <code>Server<\/code> project:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-15\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-keyword\">using<\/span> Microsoft.AspNetCore.Identity;\n<span class=\"hljs-keyword\">using<\/span> Microsoft.AspNetCore.Mvc;\n<span class=\"hljs-keyword\">using<\/span> SecureBlazorSPA.Server.Models;\n<span class=\"hljs-keyword\">using<\/span> SecureBlazorSPA.Server.Services;\n<span class=\"hljs-keyword\">using<\/span> System.Threading.Tasks;\n\n<span class=\"hljs-keyword\">namespace<\/span> <span class=\"hljs-title\">SecureBlazorSPA.Server.Controllers<\/span>\n{\n    &#91;<span class=\"hljs-meta\">ApiController<\/span>]\n    &#91;<span class=\"hljs-meta\">Route(<span class=\"hljs-meta-string\">\"api\/&#91;controller]\"<\/span>)<\/span>]\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">AccountController<\/span> : <span class=\"hljs-title\">ControllerBase<\/span>\n    {\n        <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">readonly<\/span> UserManager&lt;ApplicationUser&gt; _userManager;\n        <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">readonly<\/span> SignInManager&lt;ApplicationUser&gt; _signInManager;\n        <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">readonly<\/span> ITokenService _tokenService;\n\n        <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-title\">AccountController<\/span>(<span class=\"hljs-params\">UserManager&lt;ApplicationUser&gt; userManager, SignInManager&lt;ApplicationUser&gt; signInManager, ITokenService tokenService<\/span>)<\/span>\n        {\n            _userManager = userManager;\n            _signInManager = signInManager;\n            _tokenService = tokenService;\n        }\n\n        &#91;<span class=\"hljs-meta\">HttpPost(<span class=\"hljs-meta-string\">\"register\"<\/span>)<\/span>]\n        <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">async<\/span> Task&lt;IActionResult&gt; <span class=\"hljs-title\">Register<\/span>(<span class=\"hljs-params\">&#91;FromBody] RegisterModel model<\/span>)<\/span>\n        {\n            <span class=\"hljs-keyword\">if<\/span> (!ModelState.IsValid)\n            {\n                <span class=\"hljs-keyword\">return<\/span> BadRequest(ModelState);\n            }\n\n            <span class=\"hljs-keyword\">var<\/span> user = <span class=\"hljs-keyword\">new<\/span> ApplicationUser { UserName = model.Email, Email = model.Email };\n            <span class=\"hljs-keyword\">var<\/span> result = <span class=\"hljs-keyword\">await<\/span> _userManager.CreateAsync(user, model.Password);\n\n            <span class=\"hljs-keyword\">if<\/span> (result.Succeeded)\n            {\n                <span class=\"hljs-keyword\">await<\/span> _signInManager.SignInAsync(user, <span class=\"hljs-literal\">false<\/span>);\n                <span class=\"hljs-keyword\">return<\/span> Ok(<span class=\"hljs-keyword\">new<\/span> { Token = <span class=\"hljs-keyword\">await<\/span> _tokenService.GenerateToken(user) });\n            }\n\n            <span class=\"hljs-keyword\">foreach<\/span> (<span class=\"hljs-keyword\">var<\/span> error <span class=\"hljs-keyword\">in<\/span> result.Errors)\n            {\n                ModelState.AddModelError(<span class=\"hljs-keyword\">string<\/span>.Empty, error.Description);\n            }\n\n            <span class=\"hljs-keyword\">return<\/span> BadRequest(ModelState);\n        }\n\n        &#91;<span class=\"hljs-meta\">HttpPost(<span class=\"hljs-meta-string\">\"login\"<\/span>)<\/span>]\n        <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">async<\/span> Task&lt;IActionResult&gt; <span class=\"hljs-title\">Login<\/span>(<span class=\"hljs-params\">&#91;FromBody] LoginModel model<\/span>)<\/span>\n        {\n            <span class=\"hljs-keyword\">if<\/span> (!ModelState.IsValid)\n            {\n                <span class=\"hljs-keyword\">return<\/span> BadRequest(ModelState);\n            }\n\n            <span class=\"hljs-keyword\">var<\/span> result = <span class=\"hljs-keyword\">await<\/span> _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, <span class=\"hljs-literal\">false<\/span>);\n\n            <span class=\"hljs-keyword\">if<\/span> (result.Succeeded)\n            {\n                <span class=\"hljs-keyword\">var<\/span> user = <span class=\"hljs-keyword\">await<\/span> _userManager.FindByEmailAsync(model.Email);\n                <span class=\"hljs-keyword\">return<\/span> Ok(<span class=\"hljs-keyword\">new<\/span> { Token = <span class=\"hljs-keyword\">await<\/span> _tokenService.GenerateToken(user) });\n            }\n\n            <span class=\"hljs-keyword\">return<\/span> Unauthorized();\n        }\n    }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-15\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Create <code>RegisterModel.cs<\/code> and <code>LoginModel.cs<\/code> in the <code>Models<\/code> folder:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-16\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">RegisterModel<\/span>\n{\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">string<\/span> Email { <span class=\"hljs-keyword\">get<\/span>; <span class=\"hljs-keyword\">set<\/span>; }\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">string<\/span> Password { <span class=\"hljs-keyword\">get<\/span>; <span class=\"hljs-keyword\">set<\/span>; }\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">string<\/span> ConfirmPassword { <span class=\"hljs-keyword\">get<\/span>; <span class=\"hljs-keyword\">set<\/span>; }\n}\n\n<span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">LoginModel<\/span>\n{\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">string<\/span> Email { <span class=\"hljs-keyword\">get<\/span>; <span class=\"hljs-keyword\">set<\/span>; }\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">string<\/span> Password { <span class=\"hljs-keyword\">get<\/span>; <span class=\"hljs-keyword\">set<\/span>; }\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">bool<\/span> RememberMe { <span class=\"hljs-keyword\">get<\/span>; <span class=\"hljs-keyword\">set<\/span>; }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-16\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h2 class=\"wp-block-heading\">Implementing Security in the Blazor Client<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Step 6: Set Up Authentication State Provider<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">In the <code>Client<\/code> project, create a <code>Services<\/code> folder and add <code>CustomAuthStateProvider.cs<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-17\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-keyword\">using<\/span> Microsoft.AspNetCore.Components.Authorization;\n<span class=\"hljs-keyword\">using<\/span> System.Net.Http;\n<span class=\"hljs-keyword\">using<\/span> System.Net.Http.Headers;\n<span class=\"hljs-keyword\">using<\/span> System.Security.Claims;\n<span class=\"hljs-keyword\">using<\/span> System.Text.Json;\n<span class=\"hljs-keyword\">using<\/span> System.Threading.Tasks;\n\n<span class=\"hljs-keyword\">namespace<\/span> <span class=\"hljs-title\">SecureBlazorSPA.Client.Services<\/span>\n{\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">CustomAuthStateProvider<\/span> : <span class=\"hljs-title\">AuthenticationStateProvider<\/span>\n    {\n        <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">readonly<\/span> HttpClient _httpClient;\n\n        <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-title\">CustomAuthStateProvider<\/span>(<span class=\"hljs-params\">HttpClient httpClient<\/span>)<\/span>\n        {\n            _httpClient = httpClient;\n        }\n\n        <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">override<\/span> <span class=\"hljs-keyword\">async<\/span> Task&lt;AuthenticationState&gt; <span class=\"hljs-title\">GetAuthenticationStateAsync<\/span>(<span class=\"hljs-params\"><\/span>)<\/span>\n        {\n            <span class=\"hljs-keyword\">var<\/span> token = <span class=\"hljs-keyword\">await<\/span> _httpClient.GetStringAsync(<span class=\"hljs-string\">\"token\"<\/span>);\n\n            <span class=\"hljs-keyword\">if<\/span> (<span class=\"hljs-keyword\">string<\/span>.IsNullOrWhiteSpace(token))\n            {\n                <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-keyword\">new<\/span> AuthenticationState(<span class=\"hljs-keyword\">new<\/span> ClaimsPrincipal(<span class=\"hljs-keyword\">new<\/span> ClaimsIdentity()));\n            }\n\n            <span class=\"hljs-keyword\">var<\/span> claims = ParseClaimsFromJwt(token);\n            <span class=\"hljs-keyword\">var<\/span> identity = <span class=\"hljs-keyword\">new<\/span> ClaimsIdentity(claims, <span class=\"hljs-string\">\"jwt\"<\/span>);\n            <span class=\"hljs-keyword\">var<\/span> user = <span class=\"hljs-keyword\">new<\/span> ClaimsPrincipal(identity);\n\n            <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-keyword\">new<\/span> AuthenticationState(user);\n        }\n\n        <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">NotifyUserAuthentication<\/span>(<span class=\"hljs-params\"><span class=\"hljs-keyword\">string<\/span> token<\/span>)<\/span>\n        {\n            <span class=\"hljs-keyword\">var<\/span> authenticatedUser = <span class=\"hljs-keyword\">new<\/span> ClaimsPrincipal(<span class=\"hljs-keyword\">new<\/span> ClaimsIdentity(ParseClaimsFromJwt(token), <span class=\"hljs-string\">\"jwt\"<\/span>));\n            <span class=\"hljs-keyword\">var<\/span> authState = Task.FromResult(<span class=\"hljs-keyword\">new<\/span> AuthenticationState(authenticatedUser));\n            NotifyAuthenticationStateChanged(authState);\n        }\n\n        <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">NotifyUserLogout<\/span>(<span class=\"hljs-params\"><\/span>)<\/span>\n        {\n            <span class=\"hljs-keyword\">var<\/span> anonymousUser = <span class=\"hljs-keyword\">new<\/span> ClaimsPrincipal(<span class=\"hljs-keyword\">new<\/span> ClaimsIdentity());\n            <span class=\"hljs-keyword\">var<\/span> authState = Task.FromResult(<span class=\"hljs-keyword\">new<\/span> AuthenticationState(anonymousUser));\n            NotifyAuthenticationStateChanged(authState);\n        }\n\n        <span class=\"hljs-function\"><span class=\"hljs-keyword\">private<\/span> IEnumerable&lt;Claim&gt; <span class=\"hljs-title\">ParseClaimsFromJwt<\/span>(<span class=\"hljs-params\"><span class=\"hljs-keyword\">string<\/span> jwt<\/span>)<\/span>\n        {\n            <span class=\"hljs-keyword\">var<\/span> payload = jwt.Split(<span class=\"hljs-string\">'.'<\/span>)&#91;<span class=\"hljs-number\">1<\/span>];\n            <span class=\"hljs-keyword\">var<\/span> jsonBytes = ParseBase64WithoutPadding(payload);\n            <span class=\"hljs-keyword\">var<\/span> keyValuePairs = JsonSerializer.Deserialize&lt;Dictionary&lt;<span class=\"hljs-keyword\">string<\/span>, <span class=\"hljs-keyword\">object<\/span>&gt;&gt;(jsonBytes);\n            <span class=\"hljs-keyword\">return<\/span> keyValuePairs.Select(kvp =&gt; <span class=\"hljs-keyword\">new<\/span> Claim(kvp.Key, kvp.Value.ToString()));\n        }\n\n        <span class=\"hljs-function\"><span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">byte<\/span>&#91;] <span class=\"hljs-title\">ParseBase64WithoutPadding<\/span>(<span class=\"hljs-params\"><span class=\"hljs-keyword\">string<\/span> base64<\/span>)<\/span>\n        {\n            <span class=\"hljs-keyword\">switch<\/span> (base64.Length % <span class=\"hljs-number\">4<\/span>)\n            {\n                <span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-number\">2<\/span>: base64 += <span class=\"hljs-string\">\"==\"<\/span>; <span class=\"hljs-keyword\">break<\/span>;\n                <span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-number\">3<\/span>: base64 += <span class=\"hljs-string\">\"=\"<\/span>; <span class=\"hljs-keyword\">break<\/span>;\n            }\n            <span class=\"hljs-keyword\">return<\/span> Convert.FromBase64String(base64);\n        }\n    }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-17\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Register the <code>CustomAuthStateProvider<\/code> in <code>Program.cs<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-18\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\">builder.Services.AddAuthorizationCore();\nbuilder.Services.AddScoped&lt;CustomAuthStateProvider&gt;();\nbuilder.Services.AddScoped&lt;AuthenticationStateProvider&gt;(provider =&gt; provider.GetRequiredService&lt;CustomAuthStateProvider&gt;());<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-18\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">Step 7: Create Authentication Components<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Create a <code>Pages<\/code> folder in the <code>Client<\/code> project and add <code>Login.razor<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-19\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\">@page <span class=\"hljs-string\">\"\/login\"<\/span>\n@<span class=\"hljs-keyword\">using<\/span> Microsoft.AspNetCore.Components.Authorization\n@inject HttpClient HttpClient\n@inject CustomAuthStateProvider AuthStateProvider\n@inject NavigationManager Navigation\n\n&lt;EditForm Model=<span class=\"hljs-string\">\"loginModel\"<\/span> OnValidSubmit=<span class=\"hljs-string\">\"HandleLogin\"<\/span>&gt;\n    &lt;DataAnnotationsValidator \/&gt;\n    &lt;ValidationSummary \/&gt;\n    &lt;InputText @bind-Value=<span class=\"hljs-string\">\"loginModel.Email\"<\/span> placeholder=<span class=\"hljs-string\">\"Email\"<\/span> \/&gt;\n    &lt;InputText @bind-Value=<span class=\"hljs-string\">\"loginModel.Password\"<\/span> type=<span class=\"hljs-string\">\"password\"<\/span> placeholder=<span class=\"hljs-string\">\"Password\"<\/span> \/&gt;\n    &lt;InputCheckbox @bind-Value=<span class=\"hljs-string\">\"loginModel.RememberMe\"<\/span> \/&gt; Remember me\n    &lt;button type=<span class=\"hljs-string\">\"submit\"<\/span>&gt;Login&lt;\/button&gt;\n&lt;\/EditForm&gt;\n\n@code {\n    <span class=\"hljs-keyword\">private<\/span> LoginModel loginModel = <span class=\"hljs-keyword\">new<\/span> LoginModel();\n\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">async<\/span> Task <span class=\"hljs-title\">HandleLogin<\/span>(<span class=\"hljs-params\"><\/span>)<\/span>\n    {\n        <span class=\"hljs-keyword\">var<\/span> response = <span class=\"hljs-keyword\">await<\/span> HttpClient.PostAsJsonAsync(<span class=\"hljs-string\">\"api\/account\/login\"<\/span>, loginModel);\n\n        <span class=\"hljs-keyword\">if<\/span> (response.IsSuccessStatusCode)\n        {\n            <span class=\"hljs-keyword\">var<\/span> token = <span class=\"hljs-keyword\">await<\/span> response.Content.ReadAsStringAsync();\n            <span class=\"hljs-keyword\">await<\/span> JSRuntime.InvokeVoidAsync(<span class=\"hljs-string\">\"localStorage.setItem\"<\/span>, <span class=\"hljs-string\">\"authToken\"<\/span>, token);\n            AuthStateProvider.NotifyUserAuthentication(token);\n            Navigation.NavigateTo(<span class=\"hljs-string\">\"\/\"<\/span>);\n        }\n        <span class=\"hljs-keyword\">else<\/span>\n        {\n            <span class=\"hljs-comment\">\/\/ Handle login failure<\/span>\n        }\n    }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-19\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Create <code>Register.razor<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-20\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\">@page <span class=\"hljs-string\">\"\/register\"<\/span>\n@<span class=\"hljs-keyword\">using<\/span> Microsoft.AspNetCore.Components.Authorization\n@inject HttpClient HttpClient\n@inject CustomAuthStateProvider AuthStateProvider\n@inject NavigationManager Navigation\n\n&lt;EditForm Model=<span class=\"hljs-string\">\"registerModel\"<\/span> OnValidSubmit=<span class=\"hljs-string\">\"HandleRegister\"<\/span>&gt;\n    &lt;DataAnnotationsValidator \/&gt;\n    &lt;ValidationSummary \/&gt;\n    &lt;InputText @bind-Value=<span class=\"hljs-string\">\"registerModel.Email\"<\/span> placeholder=<span class=\"hljs-string\">\"Email\"<\/span> \/&gt;\n    &lt;InputText @bind-Value=<span class=\"hljs-string\">\"registerModel.Password\"<\/span> type=<span class=\"hljs-string\">\"password\"<\/span> placeholder=<span class=\"hljs-string\">\"Password\"<\/span> \/&gt;\n    &lt;InputText @bind-Value=<span class=\"hljs-string\">\"registerModel.ConfirmPassword\"<\/span> type=<span class=\"hljs-string\">\"password\"<\/span> placeholder=<span class=\"hljs-string\">\"Confirm Password\"<\/span> \/&gt;\n    &lt;button type=<span class=\"hljs-string\">\"submit\"<\/span>&gt;Register&lt;\/button&gt;\n&lt;\/EditForm&gt;\n\n@code {\n    <span class=\"hljs-keyword\">private<\/span> RegisterModel registerModel = <span class=\"hljs-keyword\">new<\/span> RegisterModel();\n\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">async<\/span> Task <span class=\"hljs-title\">HandleRegister<\/span>(<span class=\"hljs-params\"><\/span>)<\/span>\n    {\n        <span class=\"hljs-keyword\">var<\/span> response = <span class=\"hljs-keyword\">await<\/span> HttpClient.PostAsJsonAsync(<span class=\"hljs-string\">\"api\/account\/register\"<\/span>, registerModel);\n\n        <span class=\"hljs-keyword\">if<\/span> (response.IsSuccessStatusCode)\n        {\n            <span class=\"hljs-keyword\">var<\/span> token = <span class=\"hljs-keyword\">await<\/span> response.Content.ReadAsStringAsync();\n            <span class=\"hljs-keyword\">await<\/span> JSRuntime.InvokeVoidAsync(<span class=\"hljs-string\">\"localStorage.setItem\"<\/span>, <span class=\"hljs-string\">\"authToken\"<\/span>, token);\n            AuthStateProvider.NotifyUserAuthentication(token);\n            Navigation.NavigateTo(<span class=\"hljs-string\">\"\/\"<\/span>);\n        }\n        <span class=\"hljs-keyword\">else<\/span>\n        {\n            <span class=\"hljs-comment\">\/\/ Handle registration failure<\/span>\n        }\n    }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-20\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Update <code>App.razor<\/code> to handle authentication state:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-21\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\">&lt;CascadingAuthenticationState&gt;\n    &lt;Router AppAssembly=<span class=\"hljs-string\">\"@typeof(App).Assembly\"<\/span>&gt;\n        &lt;Found Context=<span class=\"hljs-string\">\"routeData\"<\/span>&gt;\n            &lt;AuthorizeRouteView RouteData=<span class=\"hljs-string\">\"@routeData\"<\/span> DefaultLayout=<span class=\"hljs-string\">\"@typeof(MainLayout)\"<\/span>&gt;\n                &lt;NotAuthorized&gt;\n                    &lt;h1&gt;Sorry, you<span class=\"hljs-string\">'re not authorized to view this page.&lt;\/h1&gt;\n                &lt;\/NotAuthorized&gt;\n            &lt;\/AuthorizeRouteView&gt;\n        &lt;\/Found&gt;\n        &lt;NotFound&gt;\n            &lt;h1&gt;Sorry, there'<\/span>s nothing at <span class=\"hljs-keyword\">this<\/span> address.&lt;\/h1&gt;\n        &lt;\/NotFound&gt;\n    &lt;\/Router&gt;\n&lt;\/CascadingAuthenticationState&gt;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-21\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Update <code>MainLayout.razor<\/code> to add a logout button and display the user&#8217;s name if logged in:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-22\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\">@<span class=\"hljs-keyword\">using<\/span> Microsoft.AspNetCore.Components.Authorization\n@inject CustomAuthStateProvider AuthStateProvider\n@inject NavigationManager Navigation\n\n&lt;div <span class=\"hljs-keyword\">class<\/span>=<span class=\"hljs-string\">\"top-row px-4 auth\"<\/span>&gt;\n    &lt;a href=<span class=\"hljs-string\">\"\"<\/span> @onclick=<span class=\"hljs-string\">\"Logout\"<\/span>&gt;Logout&lt;\/a&gt;\n    &lt;AuthorizeView&gt;\n        &lt;Authorized&gt;\n            &lt;span&gt;Hello, @context.User.Identity.Name&lt;\/span&gt;\n        &lt;\/Authorized&gt;\n        &lt;NotAuthorized&gt;\n            &lt;a href=<span class=\"hljs-string\">\"login\"<\/span>&gt;Login&lt;\/a&gt;\n            &lt;a href=<span class=\"hljs-string\">\"register\"<\/span>&gt;Register&lt;\/a&gt;\n        &lt;\/NotAuthorized&gt;\n    &lt;\/AuthorizeView&gt;\n&lt;\/div&gt;\n\n@code {\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">async<\/span> Task <span class=\"hljs-title\">Logout<\/span>(<span class=\"hljs-params\"><\/span>)<\/span>\n    {\n        <span class=\"hljs-keyword\">await<\/span> JSRuntime.InvokeVoidAsync(<span class=\"hljs-string\">\"localStorage.removeItem\"<\/span>, <span class=\"hljs-string\">\"authToken\"<\/span>);\n        AuthStateProvider.NotifyUserLogout();\n        Navigation.NavigateTo(<span class=\"hljs-string\">\"\/\"<\/span>);\n    }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-22\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h2 class=\"wp-block-heading\">Secure Communication<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Step 8: Secure API Endpoints<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Add the <code>[Authorize]<\/code> attribute to secure your API endpoints. For example , in the <code>WeatherForecastController<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-23\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\">&#91;<span class=\"hljs-meta\">Authorize<\/span>]\n&#91;<span class=\"hljs-meta\">ApiController<\/span>]\n&#91;<span class=\"hljs-meta\">Route(<span class=\"hljs-meta-string\">\"&#91;controller]\"<\/span>)<\/span>]\n<span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">WeatherForecastController<\/span> : <span class=\"hljs-title\">ControllerBase<\/span>\n{\n    <span class=\"hljs-comment\">\/\/ Your existing code<\/span>\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-23\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">Step 9: Handle CSRF Attacks<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">ASP.NET Core includes built-in protection against Cross-Site Request Forgery (CSRF) attacks. Make sure your forms include the anti-forgery token. In Blazor, you can use the <code>AntiForgery<\/code> component.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Add the <code>Microsoft.AspNetCore.Antiforgery<\/code> package to your project:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-24\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">dotnet<\/span> <span class=\"hljs-selector-tag\">add<\/span> <span class=\"hljs-selector-tag\">package<\/span> <span class=\"hljs-selector-tag\">Microsoft<\/span><span class=\"hljs-selector-class\">.AspNetCore<\/span><span class=\"hljs-selector-class\">.Antiforgery<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-24\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Configure the service in <code>Startup.cs<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-25\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\">services.AddAntiforgery(options =&gt; \n{\n    options.HeaderName = <span class=\"hljs-string\">\"X-CSRF-TOKEN\"<\/span>;\n});<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-25\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Use the anti-forgery token in your forms. You can inject <code>IAntiforgery<\/code> and use it in your pages or components:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-26\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\">@inject IAntiforgery Antiforgery\n\n&lt;EditForm Model=<span class=\"hljs-string\">\"loginModel\"<\/span> OnValidSubmit=<span class=\"hljs-string\">\"HandleLogin\"<\/span>&gt;\n    @Antiforgery.GetAndStoreTokens(HttpContext).RequestToken\n    &lt;DataAnnotationsValidator \/&gt;\n    &lt;ValidationSummary \/&gt;\n    &lt;InputText @bind-Value=<span class=\"hljs-string\">\"loginModel.Email\"<\/span> placeholder=<span class=\"hljs-string\">\"Email\"<\/span> \/&gt;\n    &lt;InputText @bind-Value=<span class=\"hljs-string\">\"loginModel.Password\"<\/span> type=<span class=\"hljs-string\">\"password\"<\/span> placeholder=<span class=\"hljs-string\">\"Password\"<\/span> \/&gt;\n    &lt;InputCheckbox @bind-Value=<span class=\"hljs-string\">\"loginModel.RememberMe\"<\/span> \/&gt; Remember me\n    &lt;button type=<span class=\"hljs-string\">\"submit\"<\/span>&gt;Login&lt;\/button&gt;\n&lt;\/EditForm&gt;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-26\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h2 class=\"wp-block-heading\">Data Protection<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Step 10: Encrypt Sensitive Data<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">ASP.NET Core provides data protection services for encrypting sensitive data. To use data protection, register it in <code>Startup.cs<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-27\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\">services.AddDataProtection()\n    .PersistKeysToFileSystem(<span class=\"hljs-keyword\">new<\/span> DirectoryInfo(<span class=\"hljs-string\">@\"\\\\server\\share\\directory\\\"<\/span>))\n    .SetApplicationName(<span class=\"hljs-string\">\"SecureBlazorSPA\"<\/span>);<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-27\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">Step 11: Use HTTPS<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Ensure your entire application uses HTTPS. This can be enforced in the <code>Startup.cs<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-28\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\">app.UseHttpsRedirection();<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-28\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Building secure SPAs with C# and Blazor involves a multi-faceted approach that includes securing communication, managing authentication and authorization, and protecting sensitive data. This tutorial provided a comprehensive guide to implementing these security measures in a Blazor WebAssembly application.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">By following these steps, you can create a robust and secure SPA that ensures the integrity, confidentiality, and availability of your application and user data. Remember to keep up with the latest security best practices and regularly update your dependencies to mitigate potential vulnerabilities.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introduction In web development, Single Page Applications (SPAs) have gained immense popularity due to their seamless user experience and enhanced performance. SPAs load a single HTML page and dynamically update content as the user interacts with the application. However, with the increasing complexity of SPAs, ensuring security has become a paramount concern. This tutorial will [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_genesis_hide_title":false,"_genesis_hide_breadcrumbs":false,"_genesis_hide_singular_image":false,"_genesis_hide_footer_widgets":false,"_genesis_custom_body_class":"","_genesis_custom_post_class":"","_genesis_layout":"","_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[8,4],"tags":[],"class_list":["post-1921","post","type-post","status-publish","format-standard","category-csharp","category-programming-languages","entry"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.6 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Building Secure Single Page Applications (SPAs) with C# and Blazor<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.w3computing.com\/articles\/building-secure-single-page-applications-spas-with-csharp-and-blazor\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Building Secure Single Page Applications (SPAs) with C# and Blazor\" \/>\n<meta property=\"og:description\" content=\"Introduction In web development, Single Page Applications (SPAs) have gained immense popularity due to their seamless user experience and enhanced performance. SPAs load a single HTML page and dynamically update content as the user interacts with the application. However, with the increasing complexity of SPAs, ensuring security has become a paramount concern. This tutorial will [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.w3computing.com\/articles\/building-secure-single-page-applications-spas-with-csharp-and-blazor\/\" \/>\n<meta property=\"article:published_time\" content=\"2024-06-17T22:39:09+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-06-17T22:39:15+00:00\" \/>\n<meta name=\"author\" content=\"w3compadmin\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"w3compadmin\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"4 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"TechArticle\",\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/building-secure-single-page-applications-spas-with-csharp-and-blazor\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/building-secure-single-page-applications-spas-with-csharp-and-blazor\\\/\"},\"author\":{\"name\":\"w3compadmin\",\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/#\\\/schema\\\/person\\\/a550b3e20d78bb4f79b7c6b7b53f0561\"},\"headline\":\"Building Secure Single Page Applications (SPAs) with C# and Blazor\",\"datePublished\":\"2024-06-17T22:39:09+00:00\",\"dateModified\":\"2024-06-17T22:39:15+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/building-secure-single-page-applications-spas-with-csharp-and-blazor\\\/\"},\"wordCount\":725,\"articleSection\":[\"C#\",\"Programming Languages\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/building-secure-single-page-applications-spas-with-csharp-and-blazor\\\/\",\"url\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/building-secure-single-page-applications-spas-with-csharp-and-blazor\\\/\",\"name\":\"Building Secure Single Page Applications (SPAs) with C# and Blazor\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/#website\"},\"datePublished\":\"2024-06-17T22:39:09+00:00\",\"dateModified\":\"2024-06-17T22:39:15+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/#\\\/schema\\\/person\\\/a550b3e20d78bb4f79b7c6b7b53f0561\"},\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/building-secure-single-page-applications-spas-with-csharp-and-blazor\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/building-secure-single-page-applications-spas-with-csharp-and-blazor\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/building-secure-single-page-applications-spas-with-csharp-and-blazor\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Articles Home\",\"item\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Programming Languages\",\"item\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/programming-languages\\\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"C#\",\"item\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/programming-languages\\\/csharp\\\/\"},{\"@type\":\"ListItem\",\"position\":4,\"name\":\"Building Secure Single Page Applications (SPAs) with C# and Blazor\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/#website\",\"url\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/\",\"name\":\"Developer Articles Hub\",\"description\":\"\",\"alternateName\":\"Developer Articles\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/#\\\/schema\\\/person\\\/a550b3e20d78bb4f79b7c6b7b53f0561\",\"name\":\"w3compadmin\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/wp-content\\\/litespeed\\\/avatar\\\/bd481d404e42caa2763662a3bfe825f8.jpg?ver=1780141266\",\"url\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/wp-content\\\/litespeed\\\/avatar\\\/bd481d404e42caa2763662a3bfe825f8.jpg?ver=1780141266\",\"contentUrl\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/wp-content\\\/litespeed\\\/avatar\\\/bd481d404e42caa2763662a3bfe825f8.jpg?ver=1780141266\",\"caption\":\"w3compadmin\"},\"sameAs\":[\"http:\\\/\\\/w3computing.com\\\/articles\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Building Secure Single Page Applications (SPAs) with C# and Blazor","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.w3computing.com\/articles\/building-secure-single-page-applications-spas-with-csharp-and-blazor\/","og_locale":"en_US","og_type":"article","og_title":"Building Secure Single Page Applications (SPAs) with C# and Blazor","og_description":"Introduction In web development, Single Page Applications (SPAs) have gained immense popularity due to their seamless user experience and enhanced performance. SPAs load a single HTML page and dynamically update content as the user interacts with the application. However, with the increasing complexity of SPAs, ensuring security has become a paramount concern. This tutorial will [&hellip;]","og_url":"https:\/\/www.w3computing.com\/articles\/building-secure-single-page-applications-spas-with-csharp-and-blazor\/","article_published_time":"2024-06-17T22:39:09+00:00","article_modified_time":"2024-06-17T22:39:15+00:00","author":"w3compadmin","twitter_card":"summary_large_image","twitter_misc":{"Written by":"w3compadmin","Est. reading time":"4 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"TechArticle","@id":"https:\/\/www.w3computing.com\/articles\/building-secure-single-page-applications-spas-with-csharp-and-blazor\/#article","isPartOf":{"@id":"https:\/\/www.w3computing.com\/articles\/building-secure-single-page-applications-spas-with-csharp-and-blazor\/"},"author":{"name":"w3compadmin","@id":"https:\/\/www.w3computing.com\/articles\/#\/schema\/person\/a550b3e20d78bb4f79b7c6b7b53f0561"},"headline":"Building Secure Single Page Applications (SPAs) with C# and Blazor","datePublished":"2024-06-17T22:39:09+00:00","dateModified":"2024-06-17T22:39:15+00:00","mainEntityOfPage":{"@id":"https:\/\/www.w3computing.com\/articles\/building-secure-single-page-applications-spas-with-csharp-and-blazor\/"},"wordCount":725,"articleSection":["C#","Programming Languages"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/www.w3computing.com\/articles\/building-secure-single-page-applications-spas-with-csharp-and-blazor\/","url":"https:\/\/www.w3computing.com\/articles\/building-secure-single-page-applications-spas-with-csharp-and-blazor\/","name":"Building Secure Single Page Applications (SPAs) with C# and Blazor","isPartOf":{"@id":"https:\/\/www.w3computing.com\/articles\/#website"},"datePublished":"2024-06-17T22:39:09+00:00","dateModified":"2024-06-17T22:39:15+00:00","author":{"@id":"https:\/\/www.w3computing.com\/articles\/#\/schema\/person\/a550b3e20d78bb4f79b7c6b7b53f0561"},"breadcrumb":{"@id":"https:\/\/www.w3computing.com\/articles\/building-secure-single-page-applications-spas-with-csharp-and-blazor\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.w3computing.com\/articles\/building-secure-single-page-applications-spas-with-csharp-and-blazor\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.w3computing.com\/articles\/building-secure-single-page-applications-spas-with-csharp-and-blazor\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Articles Home","item":"https:\/\/www.w3computing.com\/articles\/"},{"@type":"ListItem","position":2,"name":"Programming Languages","item":"https:\/\/www.w3computing.com\/articles\/programming-languages\/"},{"@type":"ListItem","position":3,"name":"C#","item":"https:\/\/www.w3computing.com\/articles\/programming-languages\/csharp\/"},{"@type":"ListItem","position":4,"name":"Building Secure Single Page Applications (SPAs) with C# and Blazor"}]},{"@type":"WebSite","@id":"https:\/\/www.w3computing.com\/articles\/#website","url":"https:\/\/www.w3computing.com\/articles\/","name":"Developer Articles Hub","description":"","alternateName":"Developer Articles","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.w3computing.com\/articles\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.w3computing.com\/articles\/#\/schema\/person\/a550b3e20d78bb4f79b7c6b7b53f0561","name":"w3compadmin","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.w3computing.com\/articles\/wp-content\/litespeed\/avatar\/bd481d404e42caa2763662a3bfe825f8.jpg?ver=1780141266","url":"https:\/\/www.w3computing.com\/articles\/wp-content\/litespeed\/avatar\/bd481d404e42caa2763662a3bfe825f8.jpg?ver=1780141266","contentUrl":"https:\/\/www.w3computing.com\/articles\/wp-content\/litespeed\/avatar\/bd481d404e42caa2763662a3bfe825f8.jpg?ver=1780141266","caption":"w3compadmin"},"sameAs":["http:\/\/w3computing.com\/articles"]}]}},"featured_image_src":null,"featured_image_src_square":null,"author_info":{"display_name":"w3compadmin","author_link":"https:\/\/www.w3computing.com\/articles\/author\/w3compadmin\/"},"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.w3computing.com\/articles\/wp-json\/wp\/v2\/posts\/1921","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.w3computing.com\/articles\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.w3computing.com\/articles\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.w3computing.com\/articles\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.w3computing.com\/articles\/wp-json\/wp\/v2\/comments?post=1921"}],"version-history":[{"count":3,"href":"https:\/\/www.w3computing.com\/articles\/wp-json\/wp\/v2\/posts\/1921\/revisions"}],"predecessor-version":[{"id":1925,"href":"https:\/\/www.w3computing.com\/articles\/wp-json\/wp\/v2\/posts\/1921\/revisions\/1925"}],"wp:attachment":[{"href":"https:\/\/www.w3computing.com\/articles\/wp-json\/wp\/v2\/media?parent=1921"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.w3computing.com\/articles\/wp-json\/wp\/v2\/categories?post=1921"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.w3computing.com\/articles\/wp-json\/wp\/v2\/tags?post=1921"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}