Thursday, September 12, 2019

JSON Web Token with ASP.NET Web API and Angular

What is Json Web Token (JWT)


JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. 

In simple terms, we use these tokens, to authenticate and authorize requests which are made over the internet and also to share information in forms of object typically known as Claims. You can know more in detail about Jwt on there official website.

In this article we are going to implement a simple login page in Angular, which will call an Web API endpoint to authenticate a user. If the provided credentials are authenticated, the server return a JWT token, which the client (i.e. Angular app in our case) uses for further requests involving secure transmission.

Firstly, we are going to implement the back end service which will generate the token for the first request and validate it for any further requests.

Note: I will provide a link to code base at the end of this article

Backend with Asp.Net Web API

Step 1: Create an empty Asp.Net Web API Project and add the following Nuget Packages:
  • Microsoft.AspNet.Cors
  • System.IdentityModel.Token.Jwt
  • Microsoft.Owin.Security.OAuth
  • Swashbuckle
Step 2: Create a new class named "Jwt_Authentication", which will act as the middle ware to generate the JWT token.


using Microsoft.IdentityModel.Tokens;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;

namespace AngularJwt_Api.Business
{
    public class Jwt_Authentication
    {
        private static string Secret = "ERMN05OPLoDvbTTa/QkqLNMI7cPLguaRyHzyg7n5qNBVjQmtBhz4SzYh4NBVCXi3KJHlSXKP+oi2+bXr6CUYTR==";
        public static string GenerateToken(string username)
        {

            DateTime issuedAt = DateTime.UtcNow;
            DateTime expires = DateTime.UtcNow.AddDays(7);


            var tokenHandler = new JwtSecurityTokenHandler();

            ClaimsIdentity claimsIdentity = new ClaimsIdentity(new[]
            {
                 new Claim(ClaimTypes.Name, "UserName"),
                new Claim(ClaimTypes.Email,"user@yopmail.com"),
                new Claim("DisplayName", "User"),
                new Claim(ClaimTypes.Role, "admin")
            });

            var now = DateTime.UtcNow;
            var securityKey = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(System.Text.Encoding.Default.GetBytes(Secret));
            var signingCredentials = new Microsoft.IdentityModel.Tokens.SigningCredentials(securityKey,
                Microsoft.IdentityModel.Tokens.SecurityAlgorithms.HmacSha256Signature);


            var token =
                (JwtSecurityToken)
                 tokenHandler.CreateJwtSecurityToken(issuer: "http://localhost:51888", audience: "http://localhost:400",
                    subject: claimsIdentity, notBefore: issuedAt, expires: expires, signingCredentials: signingCredentials);
            var tokenString = tokenHandler.WriteToken(token);

            return tokenString;
        }

    }
}

This method will be called, once the credentials have been verified and the token needs to generated in order to send back to the client. In the real world scenario, Claims will have the details of the logged in user, and the Issuer and Audience Url's will be of the server and client application.

(Note, these will be different for you based on the port on which you API and Angular project are hosted)

Step 3: Create a simple model class to store the incoming request from the client. I have created a class named LoginModel.cs having two string properties Username and Password.

Step 4: Now we will be create the Controller which will have the logic to implement the authentication and call the GenerateToken method we created above.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http;
using AngularJwt_Api.Models;
using AngularJwt_Api.Business;
using System.Net.Http;
using System.Net;
using System.Text;
using System.Web.Http.Cors;

namespace AngularJwt_Api.Controllers
{
 
    [EnableCors("*","*","*")]
    public class LoginController : ApiController
    {
        [HttpPost]
        [AllowAnonymous]
        public IHttpActionResult Authenticate([FromBody]LoginModel login)
        {
            bool isUsernamePasswordValid = false;

            if (login != null)
                isUsernamePasswordValid = login.Password == "admin" ? true : false;

            if (isUsernamePasswordValid)
            {
                string token = Jwt_Authentication.GenerateToken(login.Username);
             
                return Ok<string>(token);
            }
            else
            {
                return BadRequest("Login failed, invalid Username or Password.");
            }
        }

        [AuthorizeJwt]
        [HttpGet]
        public HttpResponseMessage GetSecureValues()
        {
            return this.Request.CreateResponse(HttpStatusCode.OK,
                        new { content = "Secure Content Returned" });
        }
    }
}

Here, we have two API endpoint, one which authenticates the user and the other which we will discuss later. The Authenticate method receives the LoginModel from the client and first the credentials are verified. For now we are simply matching the password but practically here we will make a call to the DB and get the credentials verified.

If the user is authenticated, the GenerateToken class is called with Username as parameter which is used in claims. You should pass on the actual User object to generate the claims.

Do remember to EnableCors in your project otherwise your angular application will not be able to communicate with the Api application.

We are all set to test are token generation logic through swagger. If you have not used Swagger before, it is a useful tool which generates documentation for your endpoints and gives you an interface to test them. It can be easily added to the project using Swashbuckle and then be accessed using /Swagger in the url of your application


Swagger to Generate Json Web Token in Asp.Net Web API


In the second image, we can see that our API return the JWT token in the Response Body. We will now move on to implementing the validation logic for incoming requests with these token.

Step 5: Create a new class names "AuthorizeJwtAttribute.cs". We will use this class to implement a custom Authorize Attribute to monitor, fetch, decode and validate the token.


using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Web;
using System.Web.Http;
using System.Web.Http.Controllers;

namespace AngularJwt_Api.Business
{
    public class AuthorizeJwtAttribute : AuthorizeAttribute
    {
        private static string Secret = "ERMN05OPLoDvbTTa/QkqLNMI7cPLguaRyHzyg7n5qNBVjQmtBhz4SzYh4NBVCXi3KJHlSXKP+oi2+bXr6CUYTR==";
        public override void OnAuthorization(HttpActionContext actionContext)
        {
            string token;
            if (!TryRetrieveToken(actionContext.Request, out token))
            {
                actionContext.Response =
                                     new HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized);
            }

            try
            {
                var now = DateTime.UtcNow;
                var securityKey = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(System.Text.Encoding.Default.GetBytes(Secret));


                SecurityToken securityToken;
                JwtSecurityTokenHandler handler = new JwtSecurityTokenHandler();
                TokenValidationParameters validationParameters = new TokenValidationParameters()
                {
                    ValidAudience = "http://localhost:50191",
                    ValidIssuer = "http://localhost:50191",
                    ValidateLifetime = true,
                    ValidateIssuerSigningKey = true,
                    LifetimeValidator = this.LifetimeValidator,
                    IssuerSigningKey = securityKey
                };
                //extract and assign the user of the jwt
                Thread.CurrentPrincipal = handler.ValidateToken(token, validationParameters, out securityToken);
                HttpContext.Current.User = handler.ValidateToken(token, validationParameters, out securityToken);
                base.OnAuthorization(actionContext);

            }
            catch (SecurityTokenValidationException e)
            {
                actionContext.Response =
                                     new HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized);
            }
            catch (Exception ex)
            {
                actionContext.Response =
                                      new HttpResponseMessage(System.Net.HttpStatusCode.InternalServerError);
            }


        }


        private static bool TryRetrieveToken(HttpRequestMessage request, out string token)
        {
            token = null;
            IEnumerable<string> authzHeaders;
            if (!request.Headers.TryGetValues("Authorization", out authzHeaders) || authzHeaders.Count() > 1)
            {
                return false;
            }
            var bearerToken = authzHeaders.ElementAt(0);
            token = bearerToken.StartsWith("Bearer ") ? bearerToken.Substring(7) : bearerToken;
            return true;
        }


        public bool LifetimeValidator(DateTime? notBefore, DateTime? expires, SecurityToken securityToken, TokenValidationParameters validationParameters)
        {
            if (expires != null)
            {
                if (DateTime.UtcNow < expires)
                {
                    return true;
                }
            }
            return false;
        }
    }
}

Here in this class, we first retrive the token using the common Secret which we used while creating the token as well. Then we provide the parameters and use the inbuilt functions to validate the token.

LifetimeValidator function is implemented to check the expiry of our token. We have implemented it to be for 7 days but in real time it is somewhere around 20 mins to 30 mins in most of the applications.

We will now utilize the GetSecureValues function to use the custom attribute just created to limit the endpoint to bearer of our Jwt token.

Json Web Token in Asp.Net Web API implemented

test the endpoint for our token through Postman, move over to the Auth tab and select the Bearer Token from the Type dropdown. Enter the token and click on Send button.

So, our API is working as expected. We have now generated and validated a Json Web Token in our Web Api project.

Client Application with Angular

Step 6: We will now create a client application using Angular 8 in Visual Studio Code and consume our API. Follow the image below and create two components login-app and nav-bar, a model named login-model and a service to communicate to our Api named login-service.

Note: You can ignore nav-bar component and all other html code and create a simple form as long as it can take a username and password as input from the user.


Angular project structure to implement Json Web Tokens

login-model.ts


export class LoginModel {
  public  Username:string = "";
 public   Password:string = "";
}

login-app.component.ts

Here we will create a reactive form in angular to take in Username and Password from the users and on click of Submit button call the service class to communicate with the API. We have also implemented basic validation messages in the form.

The console.log method will help us showcase the values we entered and response we get back from the service once we complete the implementation.

Finally we will store the token returned in either browser local storage or session storage. One stored it will be available in the memory from where it can be fetched and added in headers for all further requests.

import { LoginServiceService } from './../login-service.service';
import { Component, OnInit } from '@angular/core';
import {FormBuilder, FormGroup, Validators, FormControl} from '@angular/forms';
import {MatButtonModule} from '@angular/material/button';
import { LoginModel } from '../login-model';


@Component({
  selector: 'app-login-app',
  templateUrl: './login-app.component.html',
  styleUrls: ['./login-app.component.css']
})
export class LoginAppComponent implements OnInit {

  loginForm : FormGroup;
  loginmodel : LoginModel = new LoginModel();
  
  constructor(
    private formBuilder : FormBuilder,
    private loginService : LoginServiceService
  
  ) { }

  ngOnInit() {
    this.loginForm = this.formBuilder.group(
      {
        username : ['',Validators.required],
        password : ['',Validators.required]
      }
    );
  }

  get(key:string) : string
  {
    return this.loginForm.controls[key].value;
  }

  onSubmit() : void{
    console.log(this.loginForm.value);
    console.log(this.get('username'));
    console.log(this.get('password'));

   
    this.loginmodel.Username = this.get('username');
    this.loginmodel.Password = this.get('password');
    
    this.loginService.AuthenticateUser(this.loginmodel)
        .subscribe((response) => {
            console.log(response);
            localStorage.setItem('token', response.toString());
            sessionStorage.setItem('token', response.toString());
        })

  }

}

login-app.component.html

Basic Angular form created using Bootstrap. We have also used a simple Angular Material button for the Submit, but in case you have not worked with them before it is easier and faster to work with default bootstrap buttons for the purpose of this article.

<div class="card col-md-4 login-div offset-md-4">
      
    <h5 class="card-header">Login into the App!</h5>
   <div class="form-div card-body">
    <form [formGroup] = "loginForm" (ngSubmit) = "onSubmit($event)">
        <div class="form-group">
            <input type="text" formControlName= "username" class = "form-control" placeholder="UserName">
            <div class="error has-error alert-danger errorDiv" *ngIf = "loginForm.controls['username'].errors
            && loginForm.controls['username'].touched">
                               
                <div>Username is required</div>
            </div>
         </div>
         <div class="form-group">
            <input type="text" formControlName= "password" class = form-control placeholder="Password">
            <div class="error has-error alert-danger errorDiv" *ngIf = "loginForm.controls['password'].errors
            && loginForm.controls['password'].touched">
                <div>Password is required</div>
            </div>
         </div>
         <div>
         <button mat-raised-button color = 'primary' type="submit">  
            Login
        </button>
            <span style="float: right; margin-top: 12px">Forgot Password</span>
        </div>
    </form>
   </div>
  
</div>

nav-bar.component.ts (Optional )


import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-nav-bar',
  templateUrl: './nav-bar.component.html',
  styleUrls: ['./nav-bar.component.css']
})
export class NavBarComponent implements OnInit {

isLoggedIn: boolean

  constructor() { }

  ngOnInit() {
    this.isLoggedIn = false;
  }

}

nav-bar.component.html (Optional )


<nav class="navbar navbar-expand-lg navbar-light" style="background-color: #ffc048">
        <a class="navbar-brand" href="#">Angular Jwt App</a>
       
        <div class="collapse navbar-collapse navList" style="overflow: hidden;">
          <ul class="navbar-nav">
            <li class="nav-item" *ngIf = "!isLoggedIn">
              <a class="nav-link" href="#">Login</a>
            </li>
            <li class="nav-item" *ngIf = "isLoggedIn">
             <a class="nav-link" href="#">Hello</a>
            </li>

            <li class="nav-item mr-auto ml-2 mt-lg-0" style="margin-left: 2%">
              <a class="nav-link" href="#">Logout</a>
            </li>
        </ul>
        
        </div>
      </nav>

    

login-service.service.ts

Here we use the HttpClient module in Angular to call the method in our Api which returns the token if the user is authenticated. This method is subscribed in the login-app.component.ts

import { LoginModel } from './login-model';
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
//import {Response, RequestOptions, Headers } from '@angular/common/http';
import { HttpHeaders } from '@angular/common/http';  
import { Observable } from 'rxjs';  

@Injectable({
  providedIn: 'root'
})
export class LoginServiceService {

  base_url = "http://localhost:51888/api";
  loginModel : LoginModel;
  constructor(private http: HttpClient) { }

  AuthenticateUser(login : LoginModel){
   
    return this.http.post(this.base_url + "/Login",login)
  }

}

app.module.ts


import { LoginServiceService } from './custom-components/login-service.service';
import { LoginModel } from './custom-components/login-model';
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
//import { HttpModule } from '@angular/common/http';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { LoginAppComponent } from './custom-components/login-app/login-app.component';
import { NgForm, FormsModule, ReactiveFormsModule } from '@angular/forms';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import {MatButtonModule} from '@angular/material/button';
import {MatIconModule} from '@angular/material/icon';
import { NavBarComponent } from './custom-components/nav-bar/nav-bar.component';
import { HttpClientModule } from '@angular/common/http';


@NgModule({
  declarations: [
    AppComponent,
    LoginAppComponent,
    NavBarComponent,
    
      ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    FormsModule,
    ReactiveFormsModule,
    BrowserAnimationsModule,
    MatButtonModule,
    MatIconModule,
    HttpClientModule   
  ],
  providers: [LoginModel, LoginServiceService],
  bootstrap: [AppComponent]
})
export class AppModule { }

app.component.html


<app-nav-bar></app-nav-bar>

<app-login-app></app-login-app>

No changes are required in the app.component.ts file.

Angular App to implement Json Web Token with Asp.Net Web Api

We can now use the dummy credentials we have hard coded in our Api to test if our client app work and if the token is saved in the cookie and local storage of the browser

Json Web Token returned from Asp.Net Web Api in Angular

Json Web Token stored in browser storage

Summary

In this article we have successfully implemented Json Web Token based authentication in Asp.Net Web Api using an Angular application as a client. It is the basic skeleton above which you can build any enterprise level application.


Note: To install the Angular dependencies, open the project in VS Code and run "npm install" followed by "ng serve"

9 comments:
Write comments
  1. I appreciate the effort of the author. I found it is an informative post on bootstrap technology. I hope you shared this kind of blog in future to help both the developer and business people.
    Hire Wordpress Programmer
    Mobile App Development India
    Hire Opencart Developer
    Hire Wordpress Developer
    Hire Php Developer

    ReplyDelete
    Replies
    1. The effectiveness of IEEE Project Domains depends very much on the situation in which they are applied. In order to further improve IEEE Final Year Project Domains practices we need to explicitly describe and utilise our knowledge about software domains of software engineering Final Year Project Domains for CSE technologies. This paper suggests a modelling formalism for supporting systematic reuse of software engineering technologies during planning of software projects and improvement programmes in Final Year Projects for CSE.

      Software management seeks for decision support to identify technologies like JavaScript that meet best the goals and characteristics of a software project or improvement programme. JavaScript Training in Chennai Accessible experiences and repositories that effectively guide that technology selection are still lacking.

      Aim of technology domain analysis is to describe the class of context situations (e.g., kinds of JavaScript software projects) in which a software engineering technology JavaScript Training in Chennai can be applied successfully

      Delete
  2. Good post but I was wondering if you could write a litte more on this subject? I’d be very thankful if you could elaborate a little bit further. Appreciate it! google maps alternatives

    ReplyDelete
  3. I read that Post and got it fine and informative. Johnny Depp net worth

    ReplyDelete
  4. The website is looking bit flashy and it catches the visitors eyes. Design is pretty simple and a good user friendly interface. Johnny Depp net worth

    ReplyDelete
  5. It’s appropriate time to make some plans for the future and it is time to be happy. I have read this post and if I could I wish to suggest you few interesting things or advice. Perhaps you could write next articles referring to this article. I desire to read even more things about it! branding

    ReplyDelete
  6. Cool sites… [...]we came across a cool site that you might enjoy. Take a look if you want[...]…… https://royalcbd.com/how-to-make-cbd-gummies-at-home/

    ReplyDelete
  7. Spot on with this write-up, I truly assume this website wants much more consideration. probably be again to read much more, thanks for that info. interface design agency san francisco

    ReplyDelete
  8. Dude.. My group is not considerably into looking at, but somehow I acquired to read several articles on your blog. Its fantastic how interesting it’s for me to visit you fairly often. phone mockup

    ReplyDelete