JWTs in ASP.NET Core 2.0

A Quick Introduction to JWTs


JSON Web Tokens, often shortened with JWTs, are gathering more and more popularity in the Web environment. It is an open standard that allows transmitting data in JSON object, in a compact and secure way. They are usually used in authentication and information exchange scenarios since the data transmitted between a source and a target are digitally signed so that they can be easily verified and trusted.
For more, you can visit my previous blog here 

Securing your web API

There are many reasons you might choose to expose an API from your ASP.NET Core 2.0 app: supporting windows-based software, another web application, or maybe you’re building a SAAS product and want to give advanced users some mechanism to integrate with your platform.

But clearly, the most common (and likely) scenario is that you want to build all, or some, of your application, using front-end Single Page Application frameworks such as ReactJS, Angular, or Aurelia.

There are many ways to secure our application like OpenId Connect, OAuth2, Identity Server 4, Microsoft Identity. But today we are going for JWTs

Securing through JWTs

Here is the flow diagram which will help you to understand how JWT will work



1. A user visits your site
2. They see your client app (Angular/React etc.) login page
3. They submit their username/password
4. Your client app sends these credentials over to your ASP.NET Core web API (to an action whose sole job is to issue JWT tokens)
5. The web API checks the credentials against a user store (often a database)
6. If the credentials are valid, Your web API issues a JWT token back to the client app

That's it, nothing more than that.....

Creating a Web API

Let create a Web API application by using visual studio.
I am using VS 2017 and ASP.NET Core 2.0

 In the first case you should choose the ASP.NET Core Web Application project template, as shown in the following picture:



 Then you need to select the type of ASP.NET application, that in our case will be Web API, as we can see in the following picture:


 
 Here is our demo project



 Configuring JWT Authentication


 Now our project is ready, in order to configure support for JWT-based authentication we will make changes in the ConfigureServices method in Startup.cs file.
The following is the resulting implementation of ConfigureServices

using System.Text;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;

public void ConfigureServices(IServiceCollection services)
        {
            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearer(options =>
        {
            options.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuer = true,
                ValidateAudience = true,
                ValidateLifetime = true,
                ValidateIssuerSigningKey = true,
                ValidIssuer = Configuration["Jwt:Issuer"],
                ValidAudience = Configuration["Jwt:Issuer"],
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"]))
            };
        });

            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
        }





To consider a token valid we must:


  • validate the server that created that token (ValidateIssuer = true);
  • ensure that the recipient of the token is authorized to receive it (ValidateAudience = true);
  • check that the token is not expired and that the signing key of the issuer is valid (ValidateLifetime = true);
  • verify that the key used to sign the incoming token is part of a list of trusted keys (ValidateIssuerSigningKey = true).



In addition, we specify the values for the issuer, the audience, and the signing key.
We can store these values in the appsettings.json file to make them accessible via Configuration object:



This step configures the JWT-based authentication service. In order to make the authentication service available to the application, we need to create the Configure method in the Startup class to invoke app.UseAuthentication():

 public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseHsts();
            }

            app.UseAuthentication();

            app.UseHttpsRedirection();
            app.UseMvc();
        }





This change completes the configuration of our application to support JWT-based authentication.

Securing ASP.NET Core 2.0 Endpoints with JWTs


Once we have enabled JWT-based authentication, let's create a simple Web API to return a list of products when invoked with an HTTP GET request.
This API will be held by a new class called ProductController and model Product which we will return a response.

Below is the Product Model class:
 public class Product
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Description { get; set; }
        public decimal Price { get; set; }
}





And here is our ProdcutController:

        [HttpGet, Authorize]
        public IEnumerable<Product> Get()
        {
            var currentUser = HttpContext.User;
            var productList = new Product[] {
        new Product { Id =1 , Name = "Sunglasses",Description = "This is test description 1", Price = 10 },
        new Product { Id =1 , Name = "Mouse",Description = "This is test description 2", Price = 8 },
        new Product { Id =1 , Name = "Pen",Description = "This is test description 3", Price = 3 },
        new Product { Id =1 , Name = "Ink",Description = "This is test description 4", Price = 1 },

      };

            return productList;
        }
    }




We have added Authorize attribute in our API, requests to this endpoint will trigger the validation check of the token passed with the HTTP request.
Now let's run the application and make a GET request to the /api/product endpoint, we will get a 401 HTTP status code as a response.

We will use POSTMAN to call our API



As we can see we are getting 401 HTTP status as a response, this is due to lack of the token and our application has denied the request.

Creating JWT on Authentication

Let's add an authentication API to our application so that users can authenticate to get new JWTs.
To do that, let's create a controller called TokenController in the Controllers namespace and Login, User Model with the following code:

public class LoginModel
    {
        public string Username { get; set; }
        public string Password { get; set; }
    }

public class UserModel
    {
        public string Name { get; set; }
        public string Email { get; set; }
        public DateTime Birthdate { get; set; }
    }


The Code for Token controller goes here

[AllowAnonymous]
        [HttpPost]
        public IActionResult CreateToken([FromBody]LoginModel login)
        {
            IActionResult response = Unauthorized();
            var user = Authenticate(login);

            if (user != null)
            {
                var tokenString = BuildToken(user);
                response = Ok(new { token = tokenString });
            }

            return response;
        }

        private string BuildToken(UserModel user)
        {
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:Key"]));
            var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

            var token = new JwtSecurityToken(_config["Jwt:Issuer"],
              _config["Jwt:Issuer"],
              expires: DateTime.Now.AddMinutes(30),
              signingCredentials: creds);

            return new JwtSecurityTokenHandler().WriteToken(token);
        }

        private UserModel Authenticate(LoginModel login)
        {
            UserModel user = null;

            if (login.Username == "gagan" && login.Password == "secret")
            {
                user = new UserModel { Name = "Gagandeep Singh", Email = "gagandeep.singh@domain.com" };
            }
            return user;
        }





We have used the AllowAnonymous attribute in this API as this will be our public API, which is an API that anyone can access to get a new token after providing his credentials.

Now we will call our POST API to get the valid token, however, this API needs a valid login model.
so we are going to pass the dummy data and get a token for our-self.

The Authenticate method verifies that the provided username and password are the expected ones and returns a UserModel object representing the user. Of course, this is a trivial implementation of the authentication process. A production-ready implementation should be more accurate than all we know.

Our API will check the credentials are valid, if it is valid then API will generate a new token via the BuildToken method.
We are going to create a JSON Web Token by using the JwtSecurityToken class. We pass a few parameters to the class constructor, such as the issuer, the audience (in our case both are the same), the expiration date and time and the signature. Finally, the BuildToken method returns the token as a string, by converting it through the WriteToken method of the JwtSecurityTokenHandler class.

Geting our valid token

Let's get a JWT by making an HTTP POST request to /api/token endpoint and passing the following JSON in the request body:


{"username": "gagan", "password": "secret"}


This can be easily done with Postman or any HTTP client.



AS a response we get our token

{
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1MzkzNDEzNjYsImlzcyI6Imh0dHBzOi8vbG9jYWxob3N0OjQ0MzI3LyIsImF1ZCI6Imh0dHBzOi8vbG9jYWxob3N0OjQ0MzI3LyJ9.u94jt_CCkskmwaeJ97_af0QoFuRKPjFUYh-2TfWjMqo"
}

If we look at the value of the token, we will notice the three parts separated by a dot, as discussed in the previous article.

Now we will try again to request the list of products, as in the previous section. However, this time we will provide the token as an authentication HTTP header:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1MzkzNDEzNjYsImlzcyI6Imh0dHBzOi8vbG9jYWxob3N0OjQ0MzI3LyIsImF1ZCI6Imh0dHBzOi8vbG9jYWxob3N0OjQ0MzI3LyJ9.u94jt_CCkskmwaeJ97_af0QoFuRKPjFUYh-2TfWjMqo



So finally we can see the list of products!!!

In our next blog, we will learn how we can add claims to our token. These are usually information about the user that can be useful when authorizing access to a resource.
Claims could be, for example, user's e-mail, gender, role, city, or any other information useful to discriminate users while accessing resources

Download the source code from below link

Comments

  1. Thank you for your guide to with upgrade information
    Dot net online Training

    ReplyDelete
  2. Great Info, Thanks For Sharing , keep it up we are here to learn more

    Great! I like to share it with all my friends and hope they will also like this information.
    Power BI Training In Hyderabad
    Power BI Online Training
    Power BI Training
    Power BI Training Online

    ReplyDelete
  3. Great Info, Thanks For Sharing , keep it up we are here to learn more

    Great! I like to share it with all my friends and hope they will also like this information.
    Informatica Training In Hyderabad
    Informatica Online Training
    Informatica Training
    Informatica Training Online

    ReplyDelete

Post a Comment

Popular Posts

How to position controls using Canvas control in WPF using MVVM

Change font and size in visual studio

DataGrid in WPF MVVM