Part Three: Security in React and WebApi in ASP.NET Core C# with authentication and authorization by KeyCloak

Part three: Securing the ASP.NET Core C# REST Web API with JWT Authentication
Version 1.0
Date 2022/06/12
By Nicolas Barlatier

Nicolas Barlatier
Dev Genius

--

If you missed Part One:
Part One: Installing Keycloak with Docker and Administration

If you missed Part Two:
Part Two: Securing a front-end React application

The last Part Four:
Part Four: Calling the protected Web API from the React SPA with the access JWT Token Bearer Authorization

If you need to know more about the RS256 JWT validation :
Part 1 : Cryptography in .NET Core 5.0 : Everything you need to know about RSA and RS256 Signature and Validation.

To use the front-end React application within Docker, you can read:

Part One Dockerizing the TypeScript React App with NodeJS Vs NGINX with WSL2 Alpine Linux on Windows 10

GitHub Repository with React and Web API projects

  • React Version 18.1.0 with TypeScript
  • Web API with ASP.NET Core 5.0

You have two commits:

The first commit contains:

  • React SPA secured by the keycloak server
  • Web API secured by the Access Token with the public key from the keycloak server used to validate it

The two applications don’t communicate yet, they are only secured.

The second commit contains:

  • React SPA communicates with the Web API with the JWT Token and the CORS policy is handled

Introduction

Until now, we saw how to secure our SPA application with Keycloak.

Now, the SPA application would be pretty useless without any service to feed it back with information and data. Here we will focus on one type of Service: Rest Web API. We need to protect it.

Users interact with a SPA/Mobile App/Desktop App/Web Application/CLI/… and will be authenticating using OpenID Connect (Authorization Code Grant). The authorization server will issue an id_token (used by the application to authenticate the user) and an access_token (which is used by the application to call the API on the users behalf.)

So SPA received two tokens with the protocol OpendConnectID: ID Token and Access Token. We will see that the Access Token will be used to access our protected resource: REST API. Because this token will contain claims about Authorization.

Moreover, we will use the architecture where the Service would be an external Service; it would be hosted as an external REST API.

What does it mean ? It means the REST API would be hosted with a different machine/VM/network and accessible with the URI with a different domain than the one used to reach for the SPA.

Below the complete workflow between the SPA, external REST API and Keycloak:

Flow between SPA Keycloak and External REST API

We already saw in details the steps: 1,2 and 3

Here, we will detail the steps: 4 and 5.

The SPA will reach for the external REST API in the step 4.
The REST API will be protected by the Bearer Authentication method.

In the sept 5, the response will be returned with CORS headers because the REST API is hosted in a different domain than the one used by the React SPA.

Why using this method Bearer Authentication?

Bearer authentication (also called token authentication) is an HTTP authentication scheme that involves security tokens called bearer tokens. The name “Bearer authentication” can be understood as “give access to the bearer of this token.” The bearer token is a cryptic string, usually generated by the server in response to a login request. The client must send this token in the Authorization header when making requests to protected resources:

  • Authorization: Bearer <token>

The Bearer authentication scheme was originally created as part of OAuth 2.0 in RFC 6750, but is sometimes also used on its own. Bearer authentication should only be used over HTTPS (SSL).

In our case, what token will be used ? The Access Token indeed! Why ? Because it is the token used in the OAuth 2.0 ! Also the token contains all the needed claims to make sure the request is authorized or not to reach our protected resource: here the REST API. The SPA application uses the Access Token to call the API on behalf of the user.

In this blog, we will make our REST API totally protected. Any access to any method will need to be authorized.

Creating our REST Web Api

Let’s create our project. Here Visual Studio 2019 is used. I tend to work with Visual Code for the Front End React SPA and Visual Studio 2019 for all the Back End solution.

Click on “ASP.NET Core Web API” then Next

Creation ASP.NET Core Web API project

Let’s provide the “Project Name” and “Location”

Project Name and Location

Let’s click “Next”, we get the most important step before building our project:

Target Framework && HTTPS

Let’s set first the Target Framework by selecting the most recent one with Visual Studio 2019: .NET 5.0

.NET 5.0

Let’s click on “Configure for HTTPS” so we can make sure the “Access Token” which will be sent to the Web API will be protected by the TLS.

And let’s “Enable OpenAPI support” checked so we enable Swagger.

HTTPS && Swagger

Click on “Create”

We get the following solution:

MyWebApi Solution

Visual Studio 2019 created by default a REST Web API with one controller which will returns a random weather forecast.

It will be sufficient for our needs.

We run on debug mode the REST API by clicking on F5:

IIS Express will be run

IIS Express notification

We can see the Urls of our application MyWebApi:

MyWebApi Urls

and Visual Studio will open our Chrome browser automatically with a random port:

It will open the Swagger, very convenient to discover the services.

Let’s click on “GET”

We get a detailed view of how to call the method

Click on “Try it Out” then “Execute”

We get the response.

Swagger is a very convenient standard for discovering our REST Web API.

But I will use again Insomnia by using the HTTP GET method and sending the header: accept with the value text/plain

Insomnia : WeatherForeCast Controller HTTP GET Request and Response

So now we made sure we have a REST Web API which is running smoothly but it is not protected at all!

So let’s move on the next part:

Protecting our REST Web Api

Before updating our codebase, we need to understand: how our web api will be protected by Authorization with a JWT Access Token? How will it validate our JWT Access Token that will be sent by our SPA React application in the header called Authorization with the value
Bearer <token>

At first it was really confusing, but at the end it was indeed very simple.

First we need to understand the JWT Access Token structure, format and data.

Remember when we get directly the tokens from Insomnia:

Let get the Access Token:

eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJFMUk0RHpMWHUzUTRqMm80ZHdSRFBSOVBGUzd6bEw2MjdOaGtiSUl5WkQ0In0.eyJleHAiOjE2NTQ1NTExMzUsImlhdCI6MTY1NDU1MDgzNSwianRpIjoiNDgyOTcyMGYtNTU0MS00NTQ3LTgyZTgtNzU4YjEwYmI0YTg3IiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL3JlYWxtcy9NeVJlYWxtIiwiYXVkIjoiYWNjb3VudCIsInN1YiI6IjhiNWE3ODY2LWU5NjgtNGIyMC05MDAxLTVmZjVhZjc1ZmRjZSIsInR5cCI6IkJlYXJlciIsImF6cCI6Ik15QXBwIiwic2Vzc2lvbl9zdGF0ZSI6IjJjY2YwMjg5LWMzODYtNDJkYS05MTJlLWFhZDlmYmJiYmMyNiIsImFjciI6IjEiLCJhbGxvd2VkLW9yaWdpbnMiOlsiaHR0cDovL2xvY2FsaG9zdDozMDAwIl0sInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJkZWZhdWx0LXJvbGVzLW15cmVhbG0iLCJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiTXlBcHAiOnsicm9sZXMiOlsiQWRtaW4iXX0sImFjY291bnQiOnsicm9sZXMiOlsibWFuYWdlLWFjY291bnQiLCJtYW5hZ2UtYWNjb3VudC1saW5rcyIsInZpZXctcHJvZmlsZSJdfX0sInNjb3BlIjoib3BlbmlkIHByb2ZpbGUgZW1haWwiLCJzaWQiOiIyY2NmMDI4OS1jMzg2LTQyZGEtOTEyZS1hYWQ5ZmJiYmJjMjYiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsInByZWZlcnJlZF91c2VybmFtZSI6Im15dXNlciJ9.QBhfVFQ5GLHhoIGMAIkoq9fT_m4_nlEYKMf3KmbbyjIfvPpIPjbcfmJUm2GypoDtd3Tzn00gfDii74WoXe98phbMg9pbzyTcmzI2EnoBFKKgcmZcx_176x4xuOp5cO6Lou1-t9HWdt6l602FSmO9BUU2irrI9uluPIleP7_NLTqGBzS9GborrtqP8dJKiqm_UbGzMAgibZQOlPOVqwLnPGyfVPdrW7TlWLXRKiBV_NKpSrQjlCKtRYV0Uhv3JiIe96yIrf-8wq5-tOLrnFLwENXMTn2I4BzARPVyDKZiFV-_8Jtork9SJKcukwZ_U-25ZXq4WkMIvRsl0W0jV0J9sw

Let’s use the JWT website to decode it. We have 3 parts separated by the “.”

For example:

To understand all we need about the JWT the best article about it is :

In our Token we get:

First Part
In the header in red we have:

{
“alg”: “RS256”,
“typ”: “JWT”,
“kid”: “E1I4DzLXu3Q4j2o4dwRDPR9PFS7zlL627NhkbIIyZD4”
}

We have :

  • the algorithm: RS256
  • the Key ID (kid) : E1I4DzLXu3Q4j2o4dwRDPR9PFS7zlL627NhkbIIyZD4

This kid information will lead us to get the proper public key to validate the Access Token in our REST Web API.

In Keycloak to find the public key go to “Realm Settings” then on the “Keys” tab, make sure you are on the “Active” sub tab, then you look at the proper algorithm : we look for RS256, you are two lines possible, then you look at the kid and you see it is the last line. Now click on “Public key” button

How to find the proper line with the good algorithm and kid
How to get the Public Key

Now we know which public key will be used to validate the JWT Access Token sent by the client (like our SPA) to any protected resource: here our REST API.

Second Part

It is the main payload:

We already saw it, we will focus here on the claims:

https://www.rfc-editor.org/rfc/rfc7519#section-4

  • iss: The “iss” (issuer) claim identifies the principal that issued the
    JWT. Here it is the URI of our Keycloak server
  • aud: The “aud” (audience) claim identifies the recipients that the JWT is intended for.
  • sub: The “sub” (subject) claim identifies the principal that is the
    subject of the JWT. It must be unique.
  • typ: The “typ” (type) Header Parameter defined by [JWS] and [JWE] is used
    by JWT applications to declare the media type [IANA.MediaTypes] of
    this complete JWT. Here it is “Bearer” so we can use it

The Keycloak added the Roles associated with the User and ClientId

  • Resource_Access/MyApp/Roles [Admin]

Here we have one single Admin. But we could have several.

Moreoever we can see the clientId : MyApp.

So here what we will need in our REST API is the Role Claims for our clientid : MyApp

Third Part

It is only to make sure the main payload (Second Part) was not tampered.

JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA

Without going too deep here the formula, because keycloak uses RSA.

signature = RSA(

SHA-256(
base64UrlEncode(header) + “.” + base64UrlEncode(payload))

, private key)

We have two steps:

1°) Hashing of the header and payload with SHA-256

We hash with SHA-256 : “base64 header.base64 payload” (note the . as separator)

2°) Signature: Encoding the hash with the algorithm RSA using the private key

Then we make the signature by encoding the hash with the private key with the RSA algoritm.

Then when our protected Resource : REST API will validate the token with the public key.

Now we will see how to protect our REST API with the Authorization scheme: Bearer.

How to add the JWT Bear Authorization in our ASP.NET Core Web API ?

Now is time to know how to use Authorization in our ASP.NET Core Web Api application.
We’ll see how to secure our API endpoints.

First to help us add the proper services and middleware set up to use the JWT Bearer authentication in our application let’s install :

Microsoft.AspNetCore.Authentication.JwtBearer

With the help of the nuget at :

We will need to install the nuget compatible with .net 5.0.

Below we find all the versions and stats

we will use this link https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.JwtBearer/5.0.17

Install in our project with the command

Install-Package Microsoft.AspNetCore.Authentication.JwtBearer -Version 5.0.17

Install-Package Microsoft.AspNetCore.Authentication.JwtBearer -Version 5.0.17

Or if you prefer to use the Visual Studio interface go to the solution, right click and select Manage Nuget Package for Solution…

Manage NuGet Packages for Solution

Make sure you have the Nuget Source https://api.nuger.org/v3/index.json enabled:

https://api.nuger.org/v3/index.json

Type in JwtBearer and select Microsoft.AspNetCore.Authentication.JwtBearer

Select the good version 5.0.17 and our project MyWebApi

Click on Install

Click on I Accept

It updated the csproj file:

Now we are ready to protect our application with JwtBearer.

Here below here is sample code about how to add the JWT Bearer authentication from Microsoft source code.

But we will show how to do it in simple steps:

How to add the JWT Authentication and Authorization ?

There are 2 steps:

  • Registers all the necessary Authentication Services so the Authentication can work properly these services will be added in the DI Container
  • Call UseAuthorization to add the Authorization Middleware in our pipeline, this middleware will use the Authentication Services from the DI Container.

The Authentication Middleware will be called before the request reaches for our controller and this Middleware will set the request security context. If the security context doesn’t match the security requirement of our controller method, the request will be rejected with the HTTP 401 unauthorized status response.

So we remember what is a Middleware in the ASP.NET Core Web Api pipeline, the request goes through all the middlewares till reaching the last one of the chain which will be responsible to return the response.
The response will go back through the middleware chain in the oposite order.

We will add the Authentication Middleware in the proper pipeline location between the Middleware Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware responsible for the routing and the very last Middleware called Microsoft.AspNetCore.Routing.EndpointMiddleware responsible for handling the endpoints with controllers.

Let’s first create a dedicated folder called “Authentication”. Actually it is really an Authorization by checking the claims but the nuget used the term Authentication.

Let’s create a static helper class called ConfigureServiceAuthentificationExtension. This class will contain one extension method called ConfigureJWT

That extension method will be used in the ConfigureServices method of the Startup class which is used to add our Service in the built-in DI (Dependency Injection) container of ASP.NET Core app.

This Service will set up the Authentication.

Our Service will be added in the Startup.ConfigureServices with the IServiceCollection collection.

Here the Startup class before our modifications:

We will call our extension method ConfigureJWT which will add the necessary authentication services into the DI container with the environment with IWebHostEnvironment by injection, and the Public Key of the RSA JWT Token inserted directly into the code for now (to avoid distraction). Then we will see how to put the Public Key in the configuration file and how to use it.

services.ConfigureJTWT(_currentEnvironment.IsDevelopment(), "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp3CVbF+TZDrO6IjeFIsbWhi4vjxkLrPy2ygWBbXse7ycd2daJrFXzKmlWECrSw7wbBcv4KO0PFVtb9s5PCJGmDZOZR02xY8DgUauU+S1EWEjmEdjeC8puEOPoM/YauNWWqAtJt8146WNTN07/UsvH7YZogKcmrl7PgmEMQtHhHYCWuoe+/27Mm4UffaIWIWrdVw970SFQ2PPAYns8j9NxWHMXUQZFewEKn1mw7RrByiP99PIOMoS7GtvnkWSls9VEXrsYelVjTEaXKiaKHYX6trzP4Zg9odOTMlULmeRLYs4lVCBC/lAg/BzM+3h/3I/1xLWy9S0sfwj3YCTboBL5wIDAQAB");

we call our ConfigureJWT methode passing:

  • A boolean value to check if we are on Development environment
  • The Public Key so we can validate or not the JWT Token signed by the private key in the RSA algo.

We will see now how to configure the Service to use the JWT Bearer authentification.

For this, we use the standard extension method AddAuthentication of the static class AuthenticationServiceCollectionExtensions for the IServiceCollection services.

AddAuthentication Registers services required by authentication services and configures the Microsoft.AspNetCore.Authentication.AuthenticationOptions which we will use to tell the .NET Core to use the JWT Bearer authentification mode.

AuthenticationServiceCollectionExtensions

You can see the source code of this extension method here for ASP.NET Core 5.0.17

We will use the following extension method AddAuthentication with Action<AuthenticationOptions> configureOptions:

It will call the extension method AddAuthentication and Configure it after with our configuration options.

Below the source code of the AddAuthentication extension method

We can see it calls the AddAuthenticationCore method where we can see the services added:

services.TryAddScoped<IAuthenticationService, AuthenticationService>();services.TryAddSingleton<IClaimsTransformation, NoopClaimsTransformation>(); // Can be replaced with scoped ones that use DbContext            services.TryAddScoped<IAuthenticationHandlerProvider, AuthenticationHandlerProvider>();            services.TryAddSingleton<IAuthenticationSchemeProvider, AuthenticationSchemeProvider>();

We will see later on that IClaimsTransformation is useful for reaching for the user Roles added for the client in the JWT token generated by Keycloak.

Now let’s configure the options so that the Authentication middleware will use the JWT Bearer authentication.

Options to configure JWT Bearer authentication

We will set the following options to use the JWT Bearer Authentication Scheme:

  • AuthenticationOptions.DefaultAuthenticateScheme: Used as the default scheme by Microsoft.AspNetCore.Authentication.IAuthenticationService.AuthenticateAsync(Microsoft.AspNetCore.Http.HttpContext,System.String).
  • AuthenticationOptions.DefaultChallengeScheme: Used as the default scheme by Microsoft.AspNetCore.Authentication.IAuthenticationService.ChallengeAsync(Microsoft.AspNetCore.Http.HttpContext,System.String,Microsoft.AspNetCore.Authentication.AuthenticationProperties).
  • AuthenticationOptions.DefaultScheme

Below the link explaining the differences

We will set them all to JwtBearerDefaults.AuthenticationScheme with

public const string AuthenticationScheme = "Bearer";

AddAuthentication added the necessary service and changed the options for the Authentication Scheme to JWT Bearer. We get an AuthenticationBuilder.

With this AuthenticationBuilder we can now set up the JWT Token validation.

We will use the Nuget Microsoft.AspnetCore.Authentication.Jwtbearer and call the AddJwtBearer extension method of the static class JwtBearerExtensions to extend the AuthenticationBuilder

AuthenticationBuilder.AddJwtBearer(...)

AddJwtBearer takes as argument the

Action<JwtBearerOptions> configureOptions

We will set up in this action the following properties of JwtBearerOptions :

  • TokenValidationParameters : Contains a set of parameters that are used by a Microsoft.IdentityModel.Tokens.SecurityTokenHandler when validating a Microsoft.IdentityModel.Tokens.SecurityToken (here a JWT Token). It is where we set the Public Key to validate the token signature, the valid Issuer(s) we can accept of the token and other parameters.
  • JwtBearerEvents : Specifies events which the Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler invokes to enable developer control over the authentication process. It is where we decide what to do when the Token is validated, when Authentication got an exception is thrown, when the Authentication failed etc…
List of events which we can use

First we need a helper method to build the RSA Security Key from our JWT Public Key with is a String:

You can find a good article about this crypto part

I also wrote a very detailed article if you need to know more about the RS256 JWT validation:

The public key has a format that self-describes the algorithm of the key called a Subject Public Key Info (SPKI) which is used heavily in X509 and many other standards. The PEM header for this is “BEGIN PUBLIC KEY”, and ImportSubjectPublicKeyInfo is the correct way to import these.

To summarize each PEM label and API pairing:

“BEGIN RSA PRIVATE KEY” => RSA.ImportRSAPrivateKey

“BEGIN PRIVATE KEY” => RSA.ImportPkcs8PrivateKey

“BEGIN ENCRYPTED PRIVATE KEY” => RSA.ImportEncryptedPkcs8PrivateKey

“BEGIN RSA PUBLIC KEY” => RSA.ImportRSAPublicKey

“BEGIN PUBLIC KEY” => RSA.ImportSubjectPublicKeyInfo

We needed the last one “BEGIN PUBLIC KEY” used by Keycloak in our Public Key. I thought first we needed RSA.ImportRSAPublicKey but it failed with an exception.

I swear it was the less clear part of the codebase, it took me a while to get it right. So don’t be hard on yourself if you are confused :-)

Now let’s set up the options of JwtBearerOptions in the Action<JwtBearerOptions> which will be called by the method Configure of the ServiceCollection:IServiceCollection

Below the source code of the ServiceCollection

Even before we reach for our services.ConfigureJWT call, we can see the DI already contains all the services of the Authentication but they are in default settings.

For example they don’t have any authentication scheme

Now we we will add the JWT Bearer scheme with the extension method AddJwtBearer on our AuthenticationBuilder from the static JwtBearerExtensions class

We can see that the JWT Bearer Scheme is added into the service AuthenticationService with the call AddScheme.

Let’s see how to use AddJwtBearer

We can also see it :

Now

We can see two parts in AddJwtBearer:

  • TokenValidationParameters : used to tell how to validate our JWT Token
  • Events: used to tell how to react to specific events here when the Token is validated (we just log it to the console), when the authentication get exception (we return the HTTP 500 and add details only in dev mode)

In TokenValidationParameters we validate the JWT Token issuer hardcoded here (the value is in the “iss” claim of the JWT Token and is the URI of our realm in the Keycloak server), we validate the signature of the Token with the RsaSecurityKey, finally we validate the Token lifetime.

Now we are ready to protect our EndPoints, remember that in the Startup we already have in the Configure method the app.UseAuthorization(). This method adds the Microsoft.AspNetCore.Authorization.AuthorizationMiddleware middleware to the specified Microsoft.AspNetCore.Builder.IApplicationBuilder, which enables authorization capabilities.

When authorizing a resource that is routed using endpoint routing, this call
must appear between the calls to app.UseRouting() and app.UseEndpoints(…) for the middleware to function correctly.

See below:

So all we have to do now is to add the AuthorizeAttribute attributes with the AuthenticationSchemes set to “Bearer” like:

[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]

We can add the attribute AuthorizeAttribute to the Controller so all the methods are protected by Authorization.

Now let’s test our protected Web API without being authorized. We send our request without the JWT Token:

We get the expected HTTP 401 Unauthorized code in response. We can’t reach anymore our Web API.

Let’s update our swagger code so we can use our JWT Token easily:

This article helps:

We get the following code:

We can now use our JWT Token in the swagger:

We click on Authorize link

We copie the value of our JWT Token and click on Authorize.

Finally we can reach for our web api :)

Let’s try:

Copy from insomnia our access token which expires in 300 seconds: 5 minutes.

Paste it in the swagger form:

Click on Authorize. We get the following confirmation.

We can Logout anytime later. Click on Close to keep the Token.

We get the following window

Let’s try again the WeatherForeCast and Success! The JWT Token was validated by our Web API and we get the HTTP 200 code and expected response.

Let’s log out, fist click again on Authorize

Then on Logout

We get back the form

Click on Close and try again the Web API:

We get again the HTTP 401 code.

An excellent article to know how the JWT Bearer authentication middleware works in more details

Authorization by the JWT and Roles

We are almost done, we need to limit the access by Roles.

For now, any user with a validated JWT Token can access our Web API.
The User Role(s) are added in the JWT Token for our client: MyApp by Keycloak but are not exploited by our Web API yet.

Let’s do that now!

It is actually very simple to tell our Authentication Middleware to check for the roles in the JWT Token, we just need to update our Authorize attribute by adding the Roles like this:

[Authorize(AuthenticationSchemes = "Bearer", Roles = "Admin")]

Let’s start up again our web api.

Then Let’s try again with Swagger, remember our user has the admin role.
We add again our new generated JWT Token and try what happens:

We don’t get anymore our response but the HTTP 403: forbidden code in response.

So it seems the Web API forbids us with the JWT Token because the role didn’t match. But we are positive our JWT Token has the admin role…

Let’s look:

Yes we can see for the JWT Token in the main payload that we have for the client MyApp the roles : Admin.

Well the problem is Keycloak adds the client roles in a location where the .net core framework does not look for. We need to flatten our resource_access because Microsoft identity model doesn’t support nested claims

We need to add a ClaimsTransformer which will look at the nested claims and add the missing claims to the ClaimsIdentity of the currently authenticated user.

We will need two namespaces:

  • System.Security.Claims for the standard ClaimsPrincipal
  • Microsoft.AspNetCore.Authentication for the interface IClaimsTransformation

We will need the nuget newtonsoft.json to parse the JSON object containing the roles claims in json format.

We get at the end only 3 nugets installed.

We create a Claims Transformer which will get the roles and add them into the user ClaimsPrincipal.

We make sure to use the Claims Transformer by adding it in the Services DI container as a IClaimsTransformation instance:

services.AddTransient<IClaimsTransformation, ClaimsTransformer>()

Please be aware I hard coded the client id “MyApp” in the part. It should be used in the appsettings.json instead. Again I wanted to make the source code as simple as possible. It is not at all a production ready codebase !

content["MyApp"]["roles"]

Please find here the official microsoft documentation about how to map, customize or transform claims:

Now let’s start up again the Web Api and test!

And it works like a charm :)

Of course we can wait 5 min and try again once the JWT expires you will see a new Error will be returned. We will need either:

  • Refresh our JWT Token and use it
  • ReBuild from scratch a new JWT Token

Conclusion

We saw how to protect our very basic WebApi with the Authentication and Bearer Authorization with the JWT Token.

In the 4rd final part we will see how to call our Web API with our Access JWT Token from the React SPA application. We will have convered the complete Authorization Code Flow with the React SPA, the protected Resource Web API et our JWT Token issuer Keycloak!

At last, it is not a production ready codebase! It is a codebase to help you find your way in the very vast subject of security.

Please give me some comment, feeback.

Cheers!

The last Part Four:
Part Four: Calling the protected Web API from the React SPA with the access JWT Token Bearer Authorization

References:

--

--