Securing Webapi using Json Web Token (JWT) in web api c#

Updated to use latest :  System.IdentityModel.Tokens.Jwt -Version 5.1.4 

Jwt Web Api c# Development Environment:

  • Visual Studio 2015/2013
  • .NET Framework 4.5.2
  • we can use free tool  Restlet Client Chrome Plugin or Fiddler to test our webapi its completely up to you.
  • Nugget Packages used
    • System.IdentityModel.Tokens.Jwt -Version 5.1.4     -It will help in validating, parsing and generating JWT tokens; there are other libraries that do this task you are free to choose any package that handle JWT tokens.

Before you proceed Let’s ask our self some Prerequisite question before start working on web api c# 

Prerequisite Knowledge  – 

  • Do you know what is a HttpMessageHandler & DelegatingHandler in ASP.NET  ? If not then I would highly recommended reading this post . httpmessagehandler c# example
  • Do you know basics of jwt web api JWT(Json Web Token)? If not then Visit  jwt.io for learning more about JWT . Chris has also provided good details about JWT info.

Let’s move on to actual work that need to be done. Two basic mechanism for securing WEB API

  • Using Traditional Cookie based authentication
  •  Using Token Based Authentication – In simple words our goal is to secure data transmission between two endpoints JWT is a way to achieve.
    • Json Web Token Consist of Three parts
      • Header
      • Claim
      • Signature

Both of methods have pros and cons and that is out of the scope of this article and either of the methods should be adopted based on circumstances. we will follow Token Based Authentication. The mechanism is not complex once we get understanding of workflow. So the key is not to jump on code right away but understand  flow of request. Let’s do it

  1. User Enter username and password on mobile/web application and press login.
  2. User Credentials are sent to WEB API endpoint.
  3. We Intercept HTTP Request and check if the header has JWT token(it will not be there for the first request) if not then we verify username and password and if credentials are correct, we create a JWT token using the library and send it is back in the response body.Next time client request protected resource with this token in a header so for the subsequent request we intercept HTTP request and validate token.

Image below shows flow of information between your browser/mobile   and server.

jwt-diagram

 

Let’s start coding for our JWT WEB API C#

  1. Create a new project and name your project and solution and select ASP.NET web application

Create a new project

2. Select ASP.NET web API and change Authentication to None.

2

 

3. Click on OK to have a initial template of project.

4

 

4. Let’s add a Nuget this Latest package that will help to handle task related to jwt web api  System.IdentityModel.Tokens.Jwt

Install-Package System.IdentityModel.Tokens.Jwt -Version 5.1.4

 

Verifying The jwt web api c#  :

5. we will need to add a  class at root level that extends from DelegatingHandler  and we will override SendAsync  method. Please note the purpose of adding this class is to intercept incoming HTTP Request and Retrieve and Validate Token.

Untill this point if you don’t know what is purpose of DelegatingHandler is Please read this post before moving forward. HTTP Message Handler in Web API

I will name this class TokenValidationHandler see code snippet below and follow it carefully. click on Add to add a new class.

we wrote a custom Message Handler, we defined our own class that derived from the DelegatingHandler class and we override SendAysnc method.

This code will intercept HTTP request and validate the JWT.

 

 Generating the JWT Token  Web Api C#:

6. Next thing is we need to create a JWT after verifying the username and password with our database. For this purpose, I am going to create a controller. Let’s name it LoginController.cs 

 

we have CreateToken method that generates a token and Authenticate method receive an HTTP request and we validate the username and password and if they are valid we send back the Token.

7. Next step is where we will register Message Handler class. Add following lines in WebApiConfig.cs

       config.MessageHandlers.Add(new TokenValidationHandler ());

 

8 . Securing our controller ; Let’s decorate our Values Controller with Authorize attribute and Run the project press F5

 9 .  jwt web api c# Testing

you can use any Rest client tool to make a post call to these endpoints like Postman, fiddler or chrome extension . I will use this Chrome Restlet Client Chrome Plugin   It’s really compact and easy to use.

 

 

so here is the work flow

1- Obtaining JWT token for webapi c# :  Make a POST call to Authenticate endpoint by providing username/password  to get the token.

 

2- Using the Token to access secure endpoint of jwt web api C#:  we will use token to get access to secure resource in our case any endpoint in values controller.

As you can see I added the token in the header do notice syntax  Bearer  token .  we accessed our secured resource using JWT. It is valid for about of time we set when we generated it . if we temper with it unauthorized  code is returned.

 

Code for JWT Web Api:

Access the code for jwt web api on github repository :  JWT Authentication for Asp.Net Web Api

 

 

 

42 Responses to “Securing Webapi using Json Web Token (JWT) in web api c#

  • there is little issue in TokenValidationHandler Class when we send a blank request , only call URL and passing Header as Content-Type :application/json and calling api then is good goes to check token is available in request or not if it is not then “return base.SendAsync(request, cancellationToken);” throws an error.

    • l1f07bscs0035
      7 months ago

      Hi saineshwar . Sure thing , i will check it out this weekend i missed this scenario probably.Thanks for pointing in out i will fix it asap.

  • Gaspar
    7 months ago

    Hi, thanks for the post! I have a problem with the first call to the endPoint. The method TryRetrieveToken always return false so the line “return base.SendAsync(request, cancellationToken)” is always executed, and the token is never generated. What I’m missing? Thanks!

    • l1f07bscs0035
      7 months ago

      Hi Gasper , first thing first token generation has nothing to do with TryRetriveToken . The correct sequence of step is 1: the first call to authenticate method IHttpActionResult Authenticate([FromBody] LoginRequest login) in result call to Create token return back the token 2 : on next step we use that token to access the secured endpoint. please note the last two steps in work flow done by using postman.

  • How you have generated 401b09eab3c013d4ca54922bb802bec8fd5318192b0a75f201d8b3727429090fb337591abd3e44453b954555b7a0812e1081c39b740293f765eae731f5a65ed1

    • l1f07bscs0035
      5 months ago

      It is secret random key . In windows environment I used this random password generator and set length to 128 and include number and lower case only https://passwordsgenerator.net/

      If you more assistance let me know.

  • saurabh
    5 months ago

    Why do you get the same token always?

    • l1f07bscs0035
      4 months ago

      @saurabh. it will generate new token after it expire .see method createToken . you can customized according to your requirements.

      //set the time when it expires
      DateTime expires = DateTime.UtcNow.AddDays(7);

  • Is it possible to implement the CreateToken method in a web application in an existing LoginController while the TokenValidator is in a WebAPI project?

    I have the CreateToken in my web application and I have added the Identity.Models.Jwt Nuget package which added that package along with the Microsoft.IdentityModel.Logging and Tokens packages but I am still getting a reference not found error for the JwtSecurityTokenHandler and the Microsoft.IdentityModel reference in the CreateToken method. Can you provide any assistance with this?

  • I’ve managed to get the token generated by my web application but do you have an example of how to pass that token in the header with each API request from a web application? How should the token string be stored so that it can be referenced when building the request?

    • l1f07bscs0035
      4 months ago

      Hello Greg. please refer to Step#5 above.we need to intercept incoming HTTP Request and Retrieve and Validate Token.I would recommend to read all the steps first before start coding . it would make much more sense. also here is the code posted on github https://github.com/seanonline/Webapi_JWT_Authentication . that answers your first question . Now your second question

      “How should the token string be stored so that it can be referenced when building the request?”

      you don’t have to store the generated Json web token on server side as it is issued every time when it expire for client side there are various options . like in the github code when every thing is in .NET environment it is pretty straightforward as done in a sample code provided.

  • Chethan
    4 months ago

    SecurityToken securityToken;
    JwtSecurityTokenHandler handler = new JwtSecurityTokenHandler();
    TokenValidationParameters validationParameters = new TokenValidationParameters()
    {
    ValidAudience = “http://localhost:65151/”,
    ValidIssuer = “http://localhost:65151/”,
    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);

    Im getting exception in Thread.CurrentPrincipal = handler.ValidateToken(token, validationParameters, out securityToken); line, since the security token in null.

    this is getting executed.

    Where should i fix my code ?

    • l1f07bscs0035
      4 months ago

      Hi Chethan, I understand you are getting an exception at the certain line but to help you further. Can you please copy and paste the exact text of exception details or stack trace? Now you said you are having securityToken since at this point/line we are validating the token sent so it mean either the jwt token not provided or not in right format. see step#2 in images examples below we i use access token to request the protected data.

  • Hi, I’m following your step #2: 2- Using the Token to access secure endpoint of jwt web api C#: we will use token to get access to secure resource in our case any endpoint in values controller.

    However, I get a response of “204 No Content”. I using Chrome Restlet and passing Authorization via Get as Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImwxZjA3YnNjczAwMzUiLCJuYmYiOjE1MjI3Njc4MDgsImV4cCI6MTUyMzM3MjYwOCwiaWF0IjoxNTIyNzY3ODA5LCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjUwMTkxIiwiYXVkIjoiaHR0cDovL2xvY2FsaG9zdDo1MDE5MSJ9.gjYeD4kXP_3V3SK3EvPdzG8eKpApKcmYilrDlxs3SbU

    Any ideas?

    Mike

  • Stephane
    4 months ago

    HI Sean, thanks for your nice article! How would you manage the situation when an employee who normally have access to the web application has to get his access disable? We need to make sure he cannot use his token anymore. If I resume how to prevent user to use his unexpired token if we close his account?

  • Thanh
    3 months ago

    Hi Sean,

    I am developing REST APIs using WebAPI. The APIs are to implement ACME specification. I am getting a small issue that the APIs must support Content Type application/jose+json for request to the APIs. I wonder if you can help give me some info on how support the Content Type in WebAPIs.

    Thanks in advance
    Thanh

  • Getting the following exception, any idea? tried to do some research but without success

    {
    “Message”: “An error has occurred.”,
    “ExceptionMessage”: “IDX10214: Audience validation failed. Audiences: ‘[PII is hidden by default. Set the ‘ShowPII’ flag in IdentityModelEventSource.cs to true to reveal it.]’. Did not match: validationParameters.ValidAudience: ‘[PII is hidden by default. Set the ‘ShowPII’ flag in IdentityModelEventSource.cs to true to reveal it.]’ or validationParameters.ValidAudiences: ‘[PII is hidden by default. Set the ‘ShowPII’ flag in IdentityModelEventSource.cs to true to reveal it.]’.”,
    “ExceptionType”: “Microsoft.IdentityModel.Tokens.SecurityTokenInvalidAudienceException”,
    “StackTrace”: ” at Microsoft.IdentityModel.Tokens.Validators.ValidateAudience(IEnumerable1 audiences, SecurityToken securityToken, TokenValidationParameters validationParameters)\r\n at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateAudience(IEnumerable1 audiences, JwtSecurityToken jwtToken, TokenValidationParameters validationParameters)\r\n at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateTokenPayload(JwtSecurityToken jwtToken, TokenValidationParameters validationParameters)\r\n at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateToken(String token, TokenValidationParameters validationParameters, SecurityToken& validatedToken)\r\n at DKWEBAPI.WEBAPI_JWT_Authentication.TokenValidationHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) in C:\\Users\\meme\\Documents\\Visual Studio 2015\\Projects\\WEBAPI\\WEBAPI\\MessageHandlers\\TokenValidationHandler.vb:line 47\r\n at System.Net.Http.DelegatingHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n at System.Web.Http.HttpServer.d__24.MoveNext()”
    }

    • Nevermind, i was having different audience on token generation and validation

  • Tomer
    3 months ago

    Thank you for this article.
    How can I Authorize by user role?
    [Authorize.Manager] / [Authorize.Employee] for example.

    • l1f07bscs0035
      3 months ago

      Hi Tomer,

      you are asking about Role-based authorization. This article should get you going.

      // Restrict by user:
      [Authorize(Users=”Alice,Bob”)]
      public class ValuesController : ApiController
      {
      }

      // Restrict by role:
      [Authorize(Roles=”Administrators”)]
      public class ValuesController : ApiController
      {
      }

      • tomer
        2 months ago

        So everything working except one thing that i not sure if expected or code error related. when i try to place the token i generated in https://jwt.io/ site i am receiving Invalid Signature.
        any known fix for that?

        • l1f07bscs0035
          2 months ago

          make sure you are not missing/omitting any letter during copy or paste or any extra spaces or letter. make sure you have
          “alg”: “HS256”,
          “typ”: “JWT”

          • Tomer
            2 months ago

            It was my mistake,
            The error Invalid was because I did not copy my secret.

            Everything work now, Thank you!!

  • Narolas
    3 months ago

    Great article.

    Are LoginRequest and LoginResponse part of a framework or some other package, I can’t seem to find any reference so they’re probably custom?
    I feel like it could be useful to those files, it’s unclear what should be in them.

    Thanks you for this!

    • l1f07bscs0035
      3 months ago

      Hi Narolas ,

      I would be happy to assist you . Both of these classes(LoginRequest and LoginResponse) are custom user classes and not a part of framework and you can look at the code that is posted on github. below link will give you details about both LoginRequest and LoginResponse.

      LoginRequest and LoginResponse classes

  • Rohit
    2 months ago

    Hey man, this article is very good. And I need some more understanding.

    1. Since we have created a customHandler(TokenValidationHandler ), all the Http Requests will be first received and hence processed by this handler. (Right?)

    My confusion,

    What benefit does [Authorize] attribute brings in here on the ValuesController? Because in all incoming requests, JWTTokenValidation will anyways occur due to our messageHandler and un-Authorized user-requests “can” be rejected ?

    Sorry if it is a stupid question or if i am missing something?

    • l1f07bscs0035
      2 months ago

      Hello Rohit.

      1. Since we have created a customHandler(TokenValidationHandler ), all the Http Requests will be first received and hence processed by this handler. (Right?) Yes all http requests will be INTERCEPTED by customhandler.

      2. what benefit does [Authorize] attribute brings in here on the ValuesController
      This is good question . In general, any public method on a Controller class can be invoked via a valid URL like in our case see LoginController does not have Authorized attribute.
      In ASP.NET MVC, you use the Authorize attribute every time you have a controller method that only “known” users can invoke.

      The Authorize attribute, however, is not limited to authentication. As the name actually suggests, it also supports some basic forms of authorization. The attribute supports a couple of parameters through which developers can restrict the execution of the action method only to certain user names and/or users with a given role. Here’s an example:


      [Authorize(Roles="admin", Users="Bob, Alice")]
      public ActionResult Index()
      {
      ...
      }

      If a user is not authenticated, or doesn’t have the required user name and role, then the Authorize attribute prevents access to the method and redirects the user to the login URL. When both Roles and Users are set, the effect is combined and only users with that name and in that role are authorized. In the example above, only users Bob and Alice having the role of Admin can have access to the method.

  • Ashley Alex
    2 months ago

    Hai,
    Are we Validating the token specific to a user?

    • l1f07bscs0035
      2 months ago

      Hello ,

      So when you provide correct username and login the token is generated/validated unique every request until it expire at that point user have to login again. What exactly you are implying when you say specific to a user ?

      Thanks
      l1f07bscs0035

  • Priya
    2 months ago

    Hi,

    I am Priya. I will try for your solution. But I am facing an exception when ill hit the request from angular.
    Kinldy help me to sort it out.

    The exception is raised from Token Validator class.cs
    Thread.CurrentPrincipal = handler.ValidateToken(token, validationParameters, out securityToken);
    raised an exception as
    “IDX10709: JWT is not well formed: ‘Basic’.\nThe token needs to be in JWS or JWE Compact Serialization Format. (JWS): ‘EncodedHeader.EndcodedPayload.EncodedSignature’. (JWE): ‘EncodedProtectedHeader.EncodedEncryptedKey.EncodedInitializationVector.EncodedCiphertext.EncodedAuthenticationTag’.”}

    Other than that all the Restclient/ Postman tool is working fine for me. But not working in angular. Kindly guide me

  • Marian
    2 months ago

    Hi can you tell me why you do handler.ValidateToken 2 times and set it into Thread and also in HttpContext??

    I mean those lines:

    Thread.CurrentPrincipal = handler.ValidateToken(token, validationParameters, out securityToken);
    HttpContext.Current.User = handler.ValidateToken(token, validationParameters, out securityToken);

    • l1f07bscs0035
      2 months ago

      In short words the answer to your question is
      ASP.NET does not take care of syncing Context.User and Thread.CurrentPrincipal after PostAuthenticateRequest so we have to do it manually or in more mathematical form we are doing this

      Context.User = Thread.CurrentPrincipal = myPrincipal;

      More detailed info read between the lines below.

      The whole .NET authentication/authorization infrastructure is centered around two interfaces: IIdentity (taking care of who the user is – authentication) and IPrincipal (coupling roles with the Identity – used for authorization).

      Thread.CurrentPrincipal is the way .NET applications represent the identity of the user or service account running the process.It can hold one or more identities and allows the application to check if the principal is in a role through the IsInRole method.

  • Priya
    2 months ago

    Hi,

    I am adding headers to my HTTP request. Still, I am facing with the same exception[login button click itself]

    without this below code in webapi config its working fine in angular too.
    config.MessageHandlers.Add(new TokenValidationHandler());

    But when i am invoking this handler, that time i am not able to login into the system.

    Before login the “JWT is not well formed ” excepion arrived.

    Kindly help me to sort it out this issue.

    • l1f07bscs0035
      2 months ago

      Hey Priya , I used the same implementation above as a back end and angular 6 as a front end for a client today and it work fine . i can post some code sample that might give you idea what you are missing. or you can post your code on github i can take a look at it when i get a chance.

      Thanks
      l1f07bscs0035

  • Manjunath N
    2 months ago

    Hi,
    When calling api/values with Bearer token, getting 401 unauthorized

  • Manjunath
    2 months ago

    Hi,
    Almost there. Post to Localhost:xxxxx/api/login and receive a token. When I try to GET localhost:xxxxx/api/values I receive { status 401 unauthorized }. Don’t know what I did wrong.

    • l1f07bscs0035
      2 months ago

      Hello Manjunath

      after you get the token and make call . you have to provide token in Bearer Authentication format . check if you properly specified the authorization bearer token as described in article
      Using the Token to access secure endpoint of jwt web api C#

      Authorization Bearer – your token . look into image