Under the Hood of .NET-Based Lambda Function Parameters

Under the Hood of .NET-Based Lambda Function Parameters

We take a look at the concepts and the C# code that make lambda functions run in .NET.

We take a look at the concepts and the C# code that make lambda functions run in .NET.

This article assumes you have the relevant knowledge to set up and deploy a .NET-based lambda function. You can follow the instruction in this blog if you need some background. Now, let’s review some underlying features of this service so that you can produce more of it in the deployment phase and while it’s up in the air.

Before We Begin

Before diving into the deep water, to produce a benefit from this blog post, you should be familiar with Lambda function concepts and have AWS Explorer installed in your Visual Studio instance. Furthermore, you’d better obtain .NET Core version 2.1.3 or above.

If you haven’t experienced lambda function-based developing on C# .NET Core, you can follow my post and catch-up.

C# Lambda Handler Method Signature

Lambda function execution is trigger-based. The function receives JSON input and returns an output that is based on the invocation source type. The input includes relevant information about the source that triggered the function, whereas the output provides the necessary status of the execution. For example, the JSON input for S3 source includes relevant information about the bucket and the file that triggered the function and the operation (PUT, DELETE).

Input Parameters

A generic signature of the C# method for lambda service handlers includes two parameters: a Stream object and an ILambdaContext interface:

public APIGatewayProxyResponse LambdaStreamHandler(Stream input, ILambdaContext context)
        {
            string inputString = string.Empty;
            context.Logger.LogLine("started 'LambdaStreamHandler' method");
            // Read the stream into a string
            if (input != null)
            {
                StreamReader streamReader = new StreamReader(input);
                inputString = streamReader.ReadToEnd();
            }
            context.Logger.LogLine($"LambdaStreamHandler: received the following string: {inputString}");
            // Create APIGateway response object that contains the input string.
            // For API Gateway trigger, any other response would generate an exception
            var response = new APIGatewayProxyResponse
            {
                StatusCode = (int)HttpStatusCode.OK,
                Body = inputString,
                Headers = new Dictionary<string, string> { { "Content-Type", "application/json" } }
            };
            return response;
        }

Above is a C# lambda function that returns the input stream

Assuming the trigger is an API Gateway, the invocation of the URL ‘https:////S3ServiceNet?param1=111&param2=222'* *will produce the following JSON input (I altered some fields to avoid disclosure of sensitive data), in which you can see the query parameters inside.

{  
   "resource":"/S3ServiceNet",
   "path":"/S3ServiceNet",
   "httpMethod":"GET",
   "headers":null,
   "multiValueHeaders":null,
   "queryStringParameters":{  
      "param2":"222",
      "param1":"111"
   },
   "multiValueQueryStringParameters":{  
      "param2":[  
         "222" ],
      "param1":[  
         "111" ]
   },
   "pathParameters":null,
   "stageVariables":null,
   "requestContext":{  
      "path":"/S3ServiceNet",
      "accountId":"9337048219888888888",
      "resourceId":"x6ya4u",
      "stage":"test-invoke-stage",
      "requestId":"60f456ad16-c003f-131e8-bd034-ab017b3b1faeb",
      "identity":{  
         "cognitoIdentityPoolId":null,
         "cognitoIdentityId":null,
         "apiKey":"test-invoke-api-key",
        .........
      },
      "resourcePath":"/S3ServiceNet",
      "httpMethod":"GET",
      "extendedRequestId":"XXXXXXXXXXXX=",
      "apiId":"XXXXAASSWWEE"
   },
   "body":null,
   "isBase64Encoded":false
}

C# Object Request Example

AWS provides C# objects that wrap the common triggers’ input, such as S3 and API Gateway, so instead of parsing the JSON input, you can easily interact with a C# object.

It can be demonstrated clearly by reviewing the APIGatewayProxyRequest object*** **(under the Amazon.Lambda.APIGatewayEvents *namespace), which represents the input of API Gateway. It holds a property named RequestContext (its namespace APIGatewayProxyRequest.ProxyRequestContext), which has a property named Identity.

If you find this hierarchy and the names familiar then you have a good short term memory, since this is the same JSON input given above.

Output Parameters

Similarly to the input, the response varies depending on the trigger’s type. AWS C#.NET Core libraries include tailored response objects based on the trigger.

For example, the expected response for an API Gateway call is the object APIGatewayProxyResponse, whereas the expected response for the S3 trigger is a simple *String. *If our method returns a different object type than expected, the invocation of the lambda function will fail and throw the following error:

Execution failed due to configuration error: Malformed Lambda proxy response

A valid C# method for handling an API Gateway trigger should receive the Stream* *or APIGatewayProxyRequest object and return APIGatewayProxyResponse:

APIGatewayProxyResponse LambdaHandler(APIGatewayProxyRequest input, ILambdaContext context)

You can find more about the AWS C# library in its GitHub project. Reviewing this code will shed more light about the objects’ structure and how to use this library (aws/aws-lambda-dotnet).

Serializing From a Stream to AWS C# Objects

The .NET library mentioned above also provides a JSON serializer class that facilitates the serialization and deserialization of lambda requests and response objects. The serialization logic is based on the open-source library Newtonsoft.Json.

Being able to deserialize the input stream gives you the flexibility to define a general handler signature that receives a stream and returns an object, while the specific logic can be based on the trigger’s input.

using Amazon.Lambda.APIGatewayEvents; // required for APIGatewayProxyRequest and APIGatewayProxyResponse objects
using Amazon.Lambda.Serialization.Json; // required for JsonSerializer object
// Define a class
....
// This method receives a stream and convefts it to APIGateway request object
public object LambdaStreamHandler(Stream input, ILambdaContext context)
{
     JsonSerializer jsonSerializer = new JsonSerializer();
     APIGatewayProxyRequest request = jsonSerializer.Deserialize<APIGatewayProxyRequest>(input);
     // place your logic here
     ......
     // Create APIGateway response object.
     // For API Gateway trigger, any other response would generate an exception
     var response = new APIGatewayProxyResponse
     {
         StatusCode = (int)HttpStatusCode.OK,
         Body = string.Empty,
         Headers = new Dictionary<string, string> { { "Content-Type", "application/json" } }
     };
     return response;
}

Above is an example of a deserialization input stream.

You should note that deserialization of a mismatched object doesn’t throw any exception, therefore, it's a good idea to check the deserialized object’s properties before using them as part of your logic.

Manipulating Lambda Function's Input Parameters: The Incentives

In short, this post focuses on the entry point of an API Gateway resource, mainly on the incoming parameters’ route.

You might be wondering what the benefit of this intervention is. Why do I need to intercept in this mechanism? Well, I can think of a few reasons:

  1. Filtering variables at the API Gateway level to avoid passing them to the lambda function.
  2. Decoupling between the parameters that are sent to the API Gateway and the ones received by the lambda function; changing the name of a parameter or its format allows for the creation of a facade, which can differ from the calling service. The same applies to the response parameter.
  3. Injecting additional parameters into the lambda function, such as stage variables or generic API Gateway variables.
  4. Validating parameters before invoking the lambda function can prevent unnecessary calls, which alleviates the load and can reduce cost.
  5. Ensuring the parameters format: converting a string to an integer or escaping a string.
Another Level Above: Accessing Input Parameters via API Gateway

After integrating the API Gateway with a lambda function, by default, the request is delivered as is. If you want to interfere and manipulate the input, you need to change the configuration of the Integration Request and uncheck the option “Use Lambda Proxy integration.”

After unchecking this checkbox, the option to alter the input parameters appears below. Look for the Mapping Templates area. This is the place you can manipulate the parameters that flow into the Lambda functions.

If you keep the mapping template empty, then no parameter will flow into the lambda function. Hence, it’s essential to fill it with valid mapping. Let’s see how to configure a simple mapping template, JSON based, that copies the query parameters and their values into the input for the lambda function.

{  
  "queryStringParameters": {
  #foreach($key in $input.params().querystring.keySet())#if($foreach.index > 0),#end
  "$key":"$input.params().querystring.get($key)"#end
  }
}

The above example is looping the query string parameters and build them into a valid JSON format. Eventually, it should look like that:

You can opt to manipulate the input and create another format or convention. This capability allows standardization of the Lambda function’s input, regardless of the parameters that end-clients sends.

Let’s look at another example. The script below takes the query string parameter named param and assigns it into a parameter called var1. By that, we can implement the renaming of parameters.

{
  "queryStringParameters": { "var1":"$input.params('param')" }
}
# Equivalent to using the explicit call to querystring:
{
  "queryStringParameters": { "var1":"$input.params().querystring.get('param')" }
}

Note that if you do not surround the input with quotation marks, then the input will be interpreted as a number. This feature can be useful as a validation to the input.

This intermediate decoupling step gives a level of flexibility in designing a lambda function and API Gateway. It also can be useful for ignoring parameters, renaming parameters, or omitting parameters and passing only on the relevant ones.

Note the Input String Format

In some cases, you need to keep the query string holder to queryStringParameters,since your lambda function expects this format. For example, if you’re working with the C# lambda objects ( APIGatewayProxyRequest), you need to keep the expected JSON format for a request. Otherwise, the C# object will not be parsed and built correctly.

However, if you choose to work with a native stream as the input for the lambda function, you can change the JSON structure as you wish since the stream will be parsed in the Lambda function, based on your desired structure. You can find more information about lambda function's input in the following article.

Wrapping Up

We covered the request part of the API Gateway. However, the response can be altered as well using the same concepts of a mapping template. It can be useful to alter and standardize the response format.

API Gateways are a useful tool to receive and handle incoming requests and divert them to the relevant destination. Besides controlling the request and response format and validation, other features can be useful to manage the load and the quality of service, such as caching and throttling. I encourage you to explore its additional capabilities to improve your usability of this service.

I hope you enjoyed this post. Thanks for reading and happy coding!

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

Develop this one fundamental skill if you want to become a successful developer

Throughout my career, a multitude of people have asked me&nbsp;<em>what does it take to become a successful developer?</em>

Throughout my career, a multitude of people have asked me what does it take to become a successful developer?

It’s a common question newbies and those looking to switch careers often ask — mostly because they see the potential paycheck. There is also a Hollywood level of coolness attached to working with computers nowadays. Being a programmer or developer is akin to being a doctor or lawyer. There is job security.

But a lot of people who try to enter the profession don’t make it. So what is it that separates those who make it and those who don’t? 

Read full article here

Goodbye Javascript! Build an Authenticated Web App in C# with Blazor + ASP.NET Core 3.0

Goodbye Javascript! Build an Authenticated Web App in C# with Blazor + ASP.NET Core 3.0

In this post, you'll see why we say goodbye JavaScript and how to build an Authenticated Web App in C# with Blazor and 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

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:

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. For an even more secure way to store those values

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.

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!

Thanks for reading

If you liked this post, please do share/like it with all of your programming buddies!

Follow us on Facebook | Twitter

Further reading

JavaScript Programming Tutorial - Full JavaScript Course for Beginners

Blazor CRUD Using Google Cloud Firestore

Build amazing web apps with ASP.NET Core 3.0

Create a desktop app with Electron, React and C#

Originally published at https://developer.okta.com