How can I keep asp:button from reloading the page?

I have multiple&nbsp;<code>asp:buttons</code>&nbsp;in my application that reload the page whenever they are clicked. How do I resolve this behavior while still allowing the function of the button to work? Besides looking weird when the page reloads, I have a tab style navigation section that defaults back to the first tab every time a button is clicked. Here's an example of one button and the C# code that goes with it.

I have multiple asp:buttons in my application that reload the page whenever they are clicked. How do I resolve this behavior while still allowing the function of the button to work? Besides looking weird when the page reloads, I have a tab style navigation section that defaults back to the first tab every time a button is clicked. Here's an example of one button and the C# code that goes with it.

HTML/ASPX

<asp:Button ID="uxRequestFEMAResponseBtnT3" runat="server" Text="Generate Interim Response Email" OnClick="uxRequestFEMAResponseBtnT3_Click" />
&nbsp;<asp:TextBox ID="uxFEMARequestDateTxtBox" runat="server" style="color: red; text-align:center;"></asp:TextBox>

C#

protected void uxRequestFEMAResponseBtnT3_Click(object sender, EventArgs e)
    {
        String today = DateTime.Now.ToString("dd/MM/yyyy");
        uxFEMARequestDateTxtBox.Text = today;
    }

What I've tried so far: I have tried multiple fixes to resolve this issue. I initially thought I could resolve it by wrapping the entire body section (which includes all of the buttons) in a <asp:UpdatePanel ID="UpdatePanel1" runat="server">...'', but that did not work. Second, I tried just adding AutoPostBack="False" inside the <asp:Button..> tag, but nothing changed. I then changed all of the asp: buttons to simple html <input type="button"...> with the same onClick event. This stopped the reload, but the functionality (adding DateTime to the textbox in the C#) no longer worked. I've seen several possible jQuery solutions, but I am not sure if that will resolve my issue either. I am pretty new to ASP.NET but this seems like a common problem that anyone using the Web.Controls.UI buttons would run into. Any suggestions as to how to resolve this?

How can I slowly migrate a project from ASP .NET WebForms with VB .NET to MVC C#?

At the moment I have a legacy website written in vb .net and web forms. Its about ten years old. I want to start to migrate components of it over to C# MVC.

At the moment I have a legacy website written in vb .net and web forms. Its about ten years old. I want to start to migrate components of it over to C# MVC.

My plan is to create a separate project in the solution in C# with .NET MVC, and do all the controller code etc in there. I would need to wire up routing etc from the vb.net project though, into this project. Eventually over time the plan is to migrate the entire project over to C# with .NET MVC.

The app uses forms auth (albeit a bit of a hacky implementation of it), so if someone logs into the legacy app, their authentication should also be recognised in the "new" project/system.

How would I do this?

How to implement JWT Authentication in ASP.NET Core 3.0 API with C#

How to implement JWT Authentication in ASP.NET Core 3.0 API with C#

In this tutorial we'll go through a simple example of how to implement JWT (JSON Web Token) authentication in an ASP.NET Core 3.0 API with C#

ASP.NET Core 3.0 - JWT Authentication Tutorial with Example API

Tutorial built with ASP.NET Core 3.0

In this tutorial we'll go through a simple example of how to implement JWT (JSON Web Token) authentication in an ASP.NET Core 3.0 API with C#.

The example API has just two endpoints/routes to demonstrate authenticating with JWT and accessing a restricted route with JWT:

  • /users/authenticate - public route that accepts HTTP POST requests containing the username and password in the body. If the username and password are correct then a JWT authentication token and the user details are returned.
  • /users - secure route that accepts HTTP GET requests and returns a list of all the users in the application if the HTTP Authorization header contains a valid JWT token. If there is no auth token or the token is invalid then a 401 Unauthorized response is returned.

Tutorial Contents

  • Tools required to develop ASP.NET Core 3.0 applications
  • Running the example API locally
  • Testing the ASP.NET Core API with Postman
  • Running an Angular 8 app with the ASP.NET Core API
  • Running a React app with the ASP.NET Core API
  • Running a Vue.js app with the ASP.NET Core API
  • ASP.NET Core JWT API project structure
Tools required to run the ASP.NET Core 3.0 JWT Example Locally

To develop and run ASP.NET Core applications locally, download and install the following:

Running the ASP.NET Core JWT Authentication API Locally
  1. Download or clone the tutorial project code from https://github.com/cornflourblue/aspnet-core-3-jwt-authentication-api
  2. Start the api by running dotnet run from the command line in the project root folder (where the WebApi.csproj file is located), you should see the message Now listening on: http://localhost:4000. Follow the instructions below to test with Postman or hook up with one of the example single page applications available (Angular, React or Vue).

NOTE: You can also start the application in debug mode in VS Code by opening the project root folder in VS Code and pressing F5 or by selecting Debug -> Start Debugging from the top menu. Running in debug mode allows you to attach breakpoints to pause execution and step through the application code.

Testing the ASP.NET Core JWT Auth API with Postman

Postman is a great tool for testing APIs, you can download it at https://www.getpostman.com/.

Below are instructions on how to use Postman to authenticate a user to get a JWT token from the api, and then make an authenticated request with the JWT token to retrieve a list of users from the api.

How to authenticate a user with Postman

To authenticate a user with the api and get a JWT token follow these steps:

  1. Open a new request tab by clicking the plus (+) button at the end of the tabs.

  2. Change the http request method to "POST" with the dropdown selector on the left of the URL input field.

  3. In the URL field enter the address to the authenticate route of your local API - http://localhost:4000/users/authenticate.

  4. Select the "Body" tab below the URL field, change the body type radio button to "raw", and change the format dropdown selector to "JSON (application/json)".

  5. Enter a JSON object containing the test username and password in the "Body" textarea:

    {
        "username": "test",
        "password": "test"
    }
    
  6. Click the "Send" button, you should receive a "200 OK" response with the user details including a JWT token in the response body, make a copy of the token value because we'll be using it in the next step to make an authenticated request.

Here's a screenshot of Postman after the request is sent and the user has been authenticated:

How to make an authenticated request to retrieve all users

To make an authenticated request using the JWT token from the previous step, follow these steps:

  1. Open a new request tab by clicking the plus (+) button at the end of the tabs.
  2. Change the http request method to "GET" with the dropdown selector on the left of the URL input field.
  3. In the URL field enter the address to the users route of your local API - http://localhost:4000/users.
  4. Select the "Authorization" tab below the URL field, change the type to "Bearer Token" in the type dropdown selector, and paste the JWT token from the previous authenticate step into the "Token" field.
  5. Click the "Send" button, you should receive a "200 OK" response containing a JSON array with all the user records in the system (just the one test user in the example).

Here's a screenshot of Postman after making an authenticated request to get all users:

Running an Angular 8 client app with the ASP.NET Core JWT Auth API

For full details about the example Angular 8 application see the post Angular 8 - JWT Authentication Example & Tutorial. But to get up and running quickly just follow the below steps.

  1. Download or clone the Angular 8 tutorial code from https://github.com/cornflourblue/angular-8-jwt-authentication-example
  2. Install all required npm packages by running npm install from the command line in the project root folder (where the package.json is located).
  3. Remove or comment out the line below the comment // provider used to create fake backend located in the /src/app/app.module.ts file.
  4. Start the application by running npm start from the command line in the project root folder, this will launch a browser displaying the Angular example application and it should be hooked up with the ASP.NET Core JWT Auth API that you already have running.
Running a React client app with the ASP.NET Core JWT Auth API

For full details about the example React application see the post React - JWT Authentication Tutorial & Example. But to get up and running quickly just follow the below steps.

  1. Download or clone the React tutorial code from https://github.com/cornflourblue/react-jwt-authentication-example
  2. Install all required npm packages by running npm install from the command line in the project root folder (where the package.json is located).
  3. Remove or comment out the 2 lines below the comment // setup fake backend located in the /src/index.jsx file.
  4. Start the application by running npm start from the command line in the project root folder, this will launch a browser displaying the React example application and it should be hooked up with the ASP.NET Core JWT Auth API that you already have running.
Running a Vue.js client app with the ASP.NET Core JWT Auth API

For full details about the example VueJS JWT application see the post Vue.js + Vuex - JWT Authentication Tutorial & Example. But to get up and running quickly just follow the below steps.

  1. Download or clone the VueJS tutorial code from https://github.com/cornflourblue/vue-vuex-jwt-authentication-example
  2. Install all required npm packages by running npm install from the command line in the project root folder (where the package.json is located).
  3. Remove or comment out the 2 lines below the comment // setup fake backend located in the /src/index.js file.
  4. Start the application by running npm start from the command line in the project root folder, this will launch a browser displaying the VueJS example application and it should be hooked up with the ASP.NET Core JWT Auth API that you already have running.
ASP.NET Core JWT Authentication Project Structure

The tutorial project is organised into the following folders:
Controllers - define the end points / routes for the web api, controllers are the entry point into the web api from client applications via http requests.
Models - represent request and response models for controller methods, request models define the parameters for incoming requests, and response models can be used to define what data is returned.
Services - contain business logic, validation and data access code.
Entities - represent the application data.
Helpers - anything that doesn't fit into the above folders.

Click any of the below links to jump down to a description of each file along with its code:

  • Controllers
    • UsersController.cs
  • Entities
    • User.cs
  • Helpers
    • AppSettings.cs
    • ExtensionMethods.cs
  • Models
    • AuthenticateModel.cs
  • Services
    • UserService.cs
  • appsettings.Development.json
  • appsettings.json
  • Program.cs
  • Startup.cs
  • WebApi.csproj
ASP.NET Core JWT Users Controller

Path: /Controllers/UsersController.cs

The ASP.NET Core users controller defines and handles all routes / endpoints for the api that relate to users, this includes authentication and standard CRUD operations. Within each route the controller calls the user service to perform the action required, this enables the controller to stay 'lean' and completely separated from the business logic and data access code.

The controller actions are secured with JWT using the [Authorize] attribute, with the exception of the Authenticate method which allows public access by overriding the [Authorize] attribute on the controller with [AllowAnonymous] attribute on the action method. I chose this approach so any new action methods added to the controller will be secure by default unless explicitly made public.

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
using WebApi.Services;
using WebApi.Models;
using System.Linq;

namespace WebApi.Controllers
{
    [Authorize]
    [ApiController]
    [Route("[controller]")]
    public class UsersController : ControllerBase
    {
        private IUserService _userService;

        public UsersController(IUserService userService)
        {
            _userService = userService;
        }

        [AllowAnonymous]
        [HttpPost("authenticate")]
        public IActionResult Authenticate([FromBody]AuthenticateModel model)
        {
            var user = _userService.Authenticate(model.Username, model.Password);

            if (user == null)
                return BadRequest(new { message = "Username or password is incorrect" });

            return Ok(user);
        }

        [HttpGet]
        public IActionResult GetAll()
        {
            var users = _userService.GetAll();
            return Ok(users);
        }
    }
}
ASP.NET Core JWT User Entity

Path: /Entities/User.cs

The user entity class represents the data for a user in the application. Entity classes are used to pass data between different parts of the application (e.g. between services and controllers) and can be used to return http response data from controller action methods. If multiple types of entities or other custom data is required to be returned from a controller method then a custom model class should be created in the Models folder for the response.

namespace WebApi.Entities
{
    public class User
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Username { get; set; }
        public string Password { get; set; }
        public string Token { get; set; }
    }
}
ASP.NET Core JWT App Settings

Path: /Helpers/AppSettings.cs

The app settings class contains properties defined in the appsettings.json file and is used for accessing application settings via objects that are injected into classes using the ASP.NET Core built in dependency injection (DI) system. For example the User Service accesses app settings via an IOptions<AppSettings> appSettings object that is injected into the constructor.

Mapping of configuration sections to classes is done in the ConfigureServices method of the Startup.cs file.

namespace WebApi.Helpers
{
    public class AppSettings
    {
        public string Secret { get; set; }
    }
}
ASP.NET Core JWT Extension Methods

Path: /Helpers/ExtensionMethods.cs

Extension methods are used to add convenience methods and extra functionality to existing types in C#.

The extension methods class adds a couple of simple convenience methods for removing passwords from User instances and IEnumerable<User> collections. These methods are called by the Authenticate and GetAll methods in the UserService to ensure the user objects returned don't include passwords.

using System.Collections.Generic;
using System.Linq;
using WebApi.Entities;

namespace WebApi.Helpers
{
    public static class ExtensionMethods
    {
        public static IEnumerable<User> WithoutPasswords(this IEnumerable<User> users) {
            return users.Select(x => x.WithoutPassword());
        }

        public static User WithoutPassword(this User user) {
            user.Password = null;
            return user;
        }
    }
}
ASP.NET Core JWT Authenticate Model

Path: /Models/AuthenticateModel.cs

The authenticate model defines the parameters for incoming requests to the /users/authenticate route of the api, because it is set as the parameter to the Authenticate method of the UsersController. When an HTTP POST request is received to the route, the data from the body is bound to an instance of the AuthenticateModel, validated and passed to the method.

ASP.NET Core Data Annotations are used to automatically handle model validation, the [Required] attribute sets both the username and password as required fields so if either are missing a validation error message is returned from the api.

using System.ComponentModel.DataAnnotations;

namespace WebApi.Models
{
    public class AuthenticateModel
    {
        [Required]
        public string Username { get; set; }

        [Required]
        public string Password { get; set; }
    }
}
ASP.NET Core JWT User Service

Path: /Services/UserService.cs

The user service contains a method for authenticating user credentials and returning a JWT token, and a method for getting all users in the application.

I hardcoded the array of users in the example to keep it focused on JWT authentication, in a production application it is recommended to store user records in a database with hashed passwords.

The top of the file contains an interface that defines the user service, below that is the concrete user service class that implements the interface.

On successful authentication the Authenticate method generates a JWT (JSON Web Token) using the JwtSecurityTokenHandler class which generates a token that is digitally signed using a secret key stored in appsettings.json. The JWT token is returned to the client application which must include it in the HTTP Authorization header of subsequent requests to secure routes.

using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using WebApi.Entities;
using WebApi.Helpers;

namespace WebApi.Services
{
    public interface IUserService
    {
        User Authenticate(string username, string password);
        IEnumerable<User> GetAll();
    }

    public class UserService : IUserService
    {
        // users hardcoded for simplicity, store in a db with hashed passwords in production applications
        private List<User> _users = new List<User>
        { 
            new User { Id = 1, FirstName = "Test", LastName = "User", Username = "test", Password = "test" } 
        };

        private readonly AppSettings _appSettings;

        public UserService(IOptions<AppSettings> appSettings)
        {
            _appSettings = appSettings.Value;
        }

        public User Authenticate(string username, string password)
        {
            var user = _users.SingleOrDefault(x => x.Username == username && x.Password == password);

            // return null if user not found
            if (user == null)
                return null;

            // authentication successful so generate jwt token
            var tokenHandler = new JwtSecurityTokenHandler();
            var key = Encoding.ASCII.GetBytes(_appSettings.Secret);
            var tokenDescriptor = new SecurityTokenDescriptor
            {
                Subject = new ClaimsIdentity(new Claim[] 
                {
                    new Claim(ClaimTypes.Name, user.Id.ToString())
                }),
                Expires = DateTime.UtcNow.AddDays(7),
                SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
            };
            var token = tokenHandler.CreateToken(tokenDescriptor);
            user.Token = tokenHandler.WriteToken(token);

            return user.WithoutPassword();
        }

        public IEnumerable<User> GetAll()
        {
            return _users.WithoutPasswords();
        }
    }
}
ASP.NET Core JWT App Settings (Development)

Path: /appsettings.Development.json

Configuration file with application settings that are specific to the development environment.

{
  "Logging": {
    "LogLevel": {
      "Default": "Debug",
      "System": "Information",
      "Microsoft": "Information"
    }
  }
}
ASP.NET Core JWT App Settings

Path: /appsettings.json

Root configuration file containing application settings for all environments.

IMPORTANT: The "Secret" property is used by the api to sign and verify JWT tokens for authentication, update it with your own random string to ensure nobody else can generate a JWT to gain unauthorised access to your application.

{
  "AppSettings": {
    "Secret": "THIS IS USED TO SIGN AND VERIFY JWT TOKENS, REPLACE IT WITH YOUR OWN SECRET, IT CAN BE ANY STRING"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}
ASP.NET Core JWT Program

Path: /Program.cs

The program class is a console app that is the main entry point to start the application, it configures and launches the web api host and web server using an instance of IHostBuilder. ASP.NET Core applications require a host in which to execute.

Kestrel is the web server used in the example, it's a new cross-platform web server for ASP.NET Core that's included in new project templates by default. Kestrel is fine to use on it's own for internal applications and development, but for public facing websites and applications it should sit behind a more mature reverse proxy server (IIS, Apache, Nginx etc) that will receive HTTP requests from the internet and forward them to Kestrel after initial handling and security checks.

using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;

namespace WebApi
{
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>()
                        .UseUrls("http://localhost:4000");
                });
    }
}
ASP.NET Core JWT Startup

Path: /Startup.cs

The startup class configures the request pipeline of the application and how all requests are handled.

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using WebApi.Helpers;
using WebApi.Services;
using Microsoft.IdentityModel.Tokens;
using System.Text;
using Microsoft.AspNetCore.Authentication.JwtBearer;

namespace WebApi
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddCors();
            services.AddControllers();

            // configure strongly typed settings objects
            var appSettingsSection = Configuration.GetSection("AppSettings");
            services.Configure<AppSettings>(appSettingsSection);

            // configure jwt authentication
            var appSettings = appSettingsSection.Get<AppSettings>();
            var key = Encoding.ASCII.GetBytes(appSettings.Secret);
            services.AddAuthentication(x =>
            {
                x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            })
            .AddJwtBearer(x =>
            {
                x.RequireHttpsMetadata = false;
                x.SaveToken = true;
                x.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = new SymmetricSecurityKey(key),
                    ValidateIssuer = false,
                    ValidateAudience = false
                };
            });

            // configure DI for application services
            services.AddScoped<IUserService, UserService>();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            app.UseRouting();

            // global cors policy
            app.UseCors(x => x
                .AllowAnyOrigin()
                .AllowAnyMethod()
                .AllowAnyHeader());

            app.UseAuthentication();
            app.UseAuthorization();

            app.UseEndpoints(endpoints => {
                endpoints.MapControllers();
            });
        }
    }
}
ASP.NET Core JWT Web Api csproj

Path: /WebApi.csproj

The csproj (C# project) is an MSBuild based file that contains target framework and NuGet package dependency information for the application.

<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <TargetFramework>netcoreapp3.0</TargetFramework>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="3.0.0" />
    <PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="5.5.0" />
  </ItemGroup>
</Project>

The tutorial project is available on GitHub at https://github.com/cornflourblue/aspnet-core-3-jwt-authentication-api.

Building Authenticated Web app with C#, Blazor and ASP.NET Core 3.0

Building Authenticated Web app with C#, Blazor and ASP.NET Core 3.0

Goodbye Javascript! Now, i can Building an Authenticated Web App in C# with Blazor + ASP.NET Core 3.0.

Curious what the experience would be like to trade in Javascript for C# on the front end? You are about to find out!

Table of Contents

  • Build a Basic Website with ASP.NET Core 3.0 + Blazor
  • Add User Authentication your Blazor Web App
  • Set Up Your Okta Account to handle the ASP.NET Core 3.0 Blazor App
  • Configure Your Blazor App to use Okta as the External Auth Provider
  • Add User Login to your Blazor Web App UI
  • Test Okta Registration and Login for Your Blazor App
  • Learn More about ASP.NET Core, Blazor and Authentication

For many years, Javascript (and it’s child frameworks) have had their run of the DOM (Document Object Model) in a browser, and it took having that scripting knowledge to really manipulate client-side UI. About 2 years ago, all of that changed with the introduction of Web Assembly - which allows compiled languages to be interpreted client-side and is fully supported across all browsers now. Microsoft’s answer to this was the creation of Blazor. Allowing C# developers to build their entire stack in .NET, including UI, was an exciting proposition. For some time Blazor has been in preview but is now included as a general release on September 23rd, 2019 along with the next iteration of .NET Core - version 3.0.

In order to build with Blazor and ASP.NET Core 3.0, you need the following prerequisites installed and ready to go:

Build a Basic Website with ASP.NET Core 3.0 + Blazor

Now that you have your dev environment handy, let’s get familiar with what a basic website walkthrough would be like. There are two ways you can utilize this technology: client-side or server-side Blazor. For this example, the server-side option is the best choice for stability, as client-side Blazor is still new and working on the final release. Stay tuned for that implementation!

First, you’ll need to create a Blazor project. To get the latest Blazor project templates to work with Visual Studio or VS Code, simply install them from the command line/terminal from your base repo directory:

dotnet new -i Microsoft.AspNetCore.Blazor.Templates::3.0.0-preview9.19424.4

Visual Studio (16.3 or later) will detect that the templates have been installed and surface them to you without the need for any additional extensions. Now it’s time to scaffold your new project. From your parent directory of code repositories, execute the following command:

dotnet new blazorserver -o OktaBlazorAspNetCoreServerSide

Once it’s been run, open up the OktaBlazorAspNetCoreServerSide folder in Visual Studio Code. Once loaded, if you look in the bottom right-hand corner of the IDE you will see a permission request to add assets to the build. Select Yes.

Now that everything has been loaded up, return to your command line/terminal and run the project.

dotnet run

Launch your browser of choice and navigate to https://localhost:5001. You should see a templated website.

Add User Authentication your Blazor Web App

ASP.NET Core 3.0 has brought along with it some hefty changes to the libraries and dependencies from previous versions of .NET Core. To get started with using an external OAuth provider, like Okta, there is a NuGet package you need to add to the project. Fire up your command line/terminal window in VS Code and add the Okta .NET SDK:

dotnet add package Okta.Sdk --version 1.4.0

In 3.0, ASP.NET Core ships as part of the .NET Core shared framework. The metapackage that was used for 2.x apps is no longer used. The first line of your project file that references the Web SDK is what pulls in the shared assemblies for ASP.NET Core.

For user authentication with OAuth, there is an additional layer of information you will use, called Open ID Connect (OIDC). While much of handling authentication is baked into the new 3.0 framework, OIDC is not included, so you’ll need to add a quick reference to that.

dotnet add package Microsoft.AspNetCore.Authentication.OpenIdConnect --version 3.0.0-preview9.19424.4

Authentication works by redirecting users to the Okta website, where they will log in with their credentials, and then be returned to your site via the URL you will configure in the next section. Add the following code to the very top of your appsettings.json file, inside of the first brackets, and separate it from the rest of the settings by adding a comma after it.

"Okta": {
    "Issuer": "https://okta.okta.com/oauth2/default",
    "ClientId": "{yourClientId}",
    "ClientSecret": "{yourClientSecret}"
  }

Your file should look like this:

Just to make sure everything still can run, go ahead and execute dotnet run again.

Set Up Your Okta Account to handle the ASP.NET Core 3.0 Blazor App

Execute the following steps to configure Okta so that users can register themselves for an account.

  1. From the Administrative Dashboard, hover over Users and click Registration
  2. Click Enable Registration
  3. Save the changes

Once you have access to your account you can proceed to the Dashboard using a link like the one below: https://okta.okta.com/admin/dashboard

On the Dashboard, click Applications in the main menu and on the Application screen, click Add Application. Then select Web and click Next.

On the Create New Application screen, set the following values:

  • Name: OktaBlazorAspNetCoreServerSide

  • Base URIs: https://localhost:5001/

  • Login redirect URIs: https://localhost:5001/authorization-code/callback

Click Done, then click Edit next to General Settings on your newly created Okta app. Edit the following values: Logout redirect URIs: https://localhost:5001/signout-callback-oidc Initiate login URI: https://localhost:5001/authorization-code/callback

Once you’ve saved those values, scroll down and take note of the ClientID and ClientSecret.

ClientId refers to the client ID of the Okta application ClientSecret refers to the client secret of the Okta application Issuer will need the text {yourOktaDomain} replaced with your Okta domain, found at the top-right of the Dashboard page.

You will use your Okta account settings to update those values in the appsettings.json file in your project.

Configure Your Blazor App to use Okta as the External Auth Provider

Great! Now that Okta has been configured and is ready to go, there are a few changes that need to be made to the application startup.

Add these using statements to your Startup.cs file:

using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.IdentityModel.Tokens;

Replace all the code in the ConfigureServices method with the code below.

public void ConfigureServices(IServiceCollection services)
{
    services.AddRazorPages();
    services.AddServerSideBlazor();
    services.AddSingleton<WeatherForecastService>();
    services.AddAuthorizationCore();
    services.AddAuthentication(sharedOptions =>
    {
        sharedOptions.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        sharedOptions.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
    })
    .AddCookie()
    .AddOpenIdConnect(options =>
    {
        options.ClientId = Configuration["okta:ClientId"];
        options.ClientSecret = Configuration["okta:ClientSecret"];
        options.Authority = Configuration["okta:Issuer"];
        options.CallbackPath = "/authorization-code/callback";
        options.ResponseType = "code";
        options.SaveTokens = true;
        options.UseTokenLifetime = false;
        options.GetClaimsFromUserInfoEndpoint = true;
        options.Scope.Add("openid");
        options.Scope.Add("profile");
        options.TokenValidationParameters = new TokenValidationParameters
        {
            NameClaimType = "name"
        };
    });
}

ASP.NET Core 3.0 has new options to configure the services in this file. UseAuthorization has been newly added to 3.0 project templates.

In the Configure() method of your Startup.cs file add this line just before the app.UseEndpoints() method:

app.UseAuthentication();
app.UseAuthorization();

In this example, you'll see there's a new UseEndpoints method in Startup.cs. This is what enables the new endpoint routing system in ASP.NET Core. All 3.0 project templates use that now. Think of this as a more performant routing system.

NOTE: In the context of Blazor apps, endpoint routing is the more holistic way of handling redirects. This is covered here in depth. Also, see this documentation to learn more about it. Endpoint routing shipped in ASP.NET Core 2.2, but it didn't become the default in the templates until 3.0.

Add User Login to your Blazor Web App UI

Time to add some user personalization to this app! Open Shared/MainLayout.razor and add the following HTML right before the About link.

<AuthorizeView>
<Authorized>
            <a href="Identity/Account/Manage">Hello, @context.User.Identity.Name!</a>
            <a href="Identity/Account/LogOut">Log out</a>
    </Authorized>
    <NotAuthorized>
            <a href="Identity/Account/Register">Register</a>
            <a href="Identity/Account/Login">Log in</a>
    </NotAuthorized>
</AuthorizeView>

Using <AuthorizeView> is the easiest way to access authentication data, and is useful when you need to display a user’s name. The <AuthorizeView> component exposes a context variable of type AuthenticationState. In order to add this state to our app, open App.razor and wrap the HTML you see with <CascadingAuthenticationState> tags at the parent level. It should look like this:

<CascadingAuthenticationState>
    <Router AppAssembly="@typeof(Program).Assembly">
        ...
    </Router>
</CascadingAuthenticationState>
Test Okta Registration and Login for Your Blazor App

That’s it! To test it out, go back to the command line/terminal and execute dotnet run.

Then navigate to http://localhost:5001 in your browser. Click Login and you should be redirected to the Okta Sign-In Page.

Because you configured your Okta org for self-registration, there should be an option at the bottom of the widget to allow users to register for a new account.

Now you have a website with a working login and user registration form. Your website also allows users to recover lost passwords. By repeating these steps you can create a network of tools that your users can access all with the same login.

All of that and not one line of Javascript. The future is looking bright for C#, give it a go with Blazor!

Thank for reading! Originally published on scotch.io