Wednesday 22 January 2020

JWT Authentication with ASP.NET WEB API

we will learn how to authenticate ASP.NET WEB API using JSON Web Token(JWT). If you are new to JWT then I would like to request you to please go through with our article which briefly explains A Basic Introduction to JSON Web Token(JWT). 

Create a WEB API Project

To create a WEB API project in Visual Studio, you can follow the given steps step by step.
  1. Open Visual Studio
  2. Go to the file menu
  3. Create > Project
  4. Select Web
  5. Select “asp.net web application”
  6. Enter application name
  7. Select your project location
  8. Click on add button
It will bring up a new dialog window for select template > here I will select empty template > and then checked MVC & Web API checkbox from Add folder and core references for > and then click on Ok button.
Add NuGet package :
[su_note note_color=”#fdf6d5″]System.IdentityModel.Tokens.Jwt[/su_note]
To add NuGet package you can either use Manage NuGet Packages windows after right click on References available in Solution Explorer or you can simply use below command in Package Manager Console.
[su_note note_color=”#fdf6d5″]install-package System.IdentityModel.Tokens.Jwt [/su_note]

Create a Middleware for JWT Authentication

You need a middleware which can generate JWT and validate it based on some provided required values. To create a middleware you have to create some classes and some methods. Let’s see one by one.
Create a Folder name Auth in your application and then create given classes with some piece of code having different methods serving different purposes.
JwtAuthManager class having two methods GenerateJWTToken and GetPrincipal.
GenerateJWTToken method needs two values for username and expire_in_Minutes. the username will be used as a value to Initializes a new instance of the System.Security.Claims.Claim class with the specified claim type, and value. expire_in_Minutes act as Get or Set value for the ‘expiration’ claim.
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using Microsoft.IdentityModel.Tokens;
namespace WEBAPIJWT.Auth
{
public static class JwtAuthManager
{
public const string SecretKey = "JIOBLi6eVjBpvGtWBgJzjWd2QH0sOn5tI8rIFXSHKijXWEt/3J2jFYL79DQ1vKu+EtTYgYkwTluFRDdtF41yAQ==";
public static string GenerateJWTToken(string username, int expire_in_Minutes = 10)
{
var symmetric_Key = Convert.FromBase64String(SecretKey);
var token_Handler = new JwtSecurityTokenHandler();
var now = DateTime.UtcNow;
var securitytokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new[]
{
new Claim(ClaimTypes.Name, username)
}),
Expires = now.AddMinutes(Convert.ToInt32(expire_in_Minutes)),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(symmetric_Key), SecurityAlgorithms.HmacSha256Signature)
};
var stoken = token_Handler.CreateToken(securitytokenDescriptor);
var token = token_Handler.WriteToken(stoken);
return token;
}
public static ClaimsPrincipal GetPrincipal(string token)
{
try
{
var tokenHandler = new JwtSecurityTokenHandler();
var jwtToken = tokenHandler.ReadToken(token) as JwtSecurityToken;
if (jwtToken == null)
return null;
var symmetricKey = Convert.FromBase64String(SecretKey);
var validationParameters = new TokenValidationParameters()
{
RequireExpirationTime = true,
ValidateIssuer = false,
ValidateAudience = false,
IssuerSigningKey = new SymmetricSecurityKey(symmetricKey)
};
SecurityToken securityToken;
var principal = tokenHandler.ValidateToken(token, validationParameters, out securityToken);
return principal;
}
catch (Exception e)
{
return null;
}
}
}
}
view rawJwtAuthManager.cs hosted with ❤ by GitHub
You can use HMACSHA256 to create your own SecretKey. It belongs to System.Security.Cryptography namespace. Use below code to generate your own secret code
[su_note note_color=”#fdf6d5″]var hmac = new HMACSHA256(); var key = Convert.ToBase64String(hmac.Key);[/su_note]
As of now, you might be thinking I’ve not written any single word for the second method which is GetPrinciple of JwtAuthManager class. Don’t worry, we’ll go through with this later because to generate token only GenerateJWTToken method will work.
When user request with the valid required credential to get JSON Web Token, GenerateJWTToken comes in action and create a token for that particular user. Have a look at below image where you can see what different things combined in order to create a token.
Fine! I hope till now you have created Token successfully with the help of above code, now next thing is to validate it when that particular user again requests with the generated token. We use below code to validate the token. Have a look.
using System;
using System.Collections.Generic;
using System.Security.Claims;
using System.Security.Principal;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http.Filters;
namespace WEBAPIJWT.Auth
{
public class JwtAuthentication : Attribute, IAuthenticationFilter
{
public string Realm { get; set; }
public bool AllowMultiple => false;
public async Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
{
var request = context.Request;
var authorization = request.Headers.Authorization;
// checking request header value having required scheme "Bearer" or not.
if (authorization == null || authorization.Scheme != "Bearer" || string.IsNullOrEmpty(authorization.Parameter))
{
context.ErrorResult = new AuthFailureResult("JWT Token is Missing", request);
return;
}
// Getting Token value from header values.
var token = authorization.Parameter;
var principal = await AuthJwtToken(token);
if (principal == null)
{
context.ErrorResult = new AuthFailureResult("Invalid JWT Token", request);
}
else
{
context.Principal = principal;
}
}
private static bool ValidateToken(string token, out string username)
{
username = null;
var simplePrinciple = JwtAuthManager.GetPrincipal(token);
if (simplePrinciple == null)
return false;
var identity = simplePrinciple.Identity as ClaimsIdentity;
if (identity == null)
return false;
if (!identity.IsAuthenticated)
return false;
var usernameClaim = identity.FindFirst(ClaimTypes.Name);
username = usernameClaim?.Value;
if (string.IsNullOrEmpty(username))
return false;
// You can implement more validation to check whether username exists in your DB or not or something else.
return true;
}
protected Task<IPrincipal> AuthJwtToken(string token)
{
string username;
if (ValidateToken(token, out username))
{
//to get more information from DB in order to build local identity based on username
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, username)
// you can add more claims if needed like Roles ( Admin or normal user or something else)
};
var identity = new ClaimsIdentity(claims, "Jwt");
IPrincipal user = new ClaimsPrincipal(identity);
return Task.FromResult(user);
}
return Task.FromResult<IPrincipal>(null);
}
public Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken)
{
Challenge(context);
return Task.FromResult(0);
}
private void Challenge(HttpAuthenticationChallengeContext context)
{
string parameter = null;
if (!string.IsNullOrEmpty(Realm))
parameter = "realm=\"" + Realm + "\"";
context.ChallengeWith("Bearer", parameter);
}
}
}
JwtAuthentication class inheriting Attribute class and IAuthenticationFilter. IAuthenticationFilter is an interface having two declared function AuthenticateAsync and ChallengeAsync.
[su_box title=”Note :” box_color=”#faf62b” title_color=”#151111″]Attribute class represent a base class with a custom attribute. IAuthenticationFilter Interface Define a filter that performs authentication.[/su_box]
AuthenticateAsync invokes first when sending a request with the token. Two parameter context and cancellationToken belongs to AuthenticateAsync is used to get a request from the user. context will have the authentication context and cancellationToken will have the token to monitor for cancellation requests.
ValidateToken method having two parameter token and username will validate requested token is exact same or not issued to that particular user based on username. Here comes GetPrincipal method in action, GetPrinciple read token with same and validate it with TokenValidationParameters.
While Validating token, there are chances that authentication might be failed if a request having token is not valid. You can deal with same as given below code
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http;
namespace WEBAPIJWT.Auth
{
public class AuthFailureResult : IHttpActionResult
{
public AuthFailureResult(string reasonPhrase, HttpRequestMessage request)
{
ReasonPhrase = reasonPhrase;
Request = request;
}
public string ReasonPhrase { get; }
public HttpRequestMessage Request { get; }
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
return Task.FromResult(Execute());
}
private HttpResponseMessage Execute()
{
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.Unauthorized)
{
RequestMessage = Request,
ReasonPhrase = ReasonPhrase
};
return response;
}
}
}
AuthFailureResult class inherit IHttpActionResult Interface. You have to implement ExecuteAsync that belong to IHttpActionResult. ExecuteAsync is used to perform a task contains the System.Net.Http.HttpResponseMessage when completed.
you can use below code to add authorization in the header.
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http;
namespace WEBAPIJWT.Auth
{
public class UnauthorizedResult : IHttpActionResult
{
public UnauthorizedResult(AuthenticationHeaderValue authHeaderValue, IHttpActionResult innerResult)
{
AuthHeaderValue = authHeaderValue;
InnerResult = innerResult;
}
public AuthenticationHeaderValue AuthHeaderValue { get; }
public IHttpActionResult InnerResult { get; }
public async Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
HttpResponseMessage response = await InnerResult.ExecuteAsync(cancellationToken);
if (response.StatusCode == HttpStatusCode.Unauthorized)
{
// Only add one challenge per authentication scheme.
if (response.Headers.WwwAuthenticate.All(h => h.Scheme != AuthHeaderValue.Scheme))
{
response.Headers.WwwAuthenticate.Add(AuthHeaderValue);
}
}
return response;
}
}
}
view rawUnauthResult.cs hosted with ❤ by GitHub

Create WEB API Controller

You need to create two different actions one for generating a token, send back to the user and second one for validating that token and expose requested data by the user. You can have both actions in the same controller or can have two separate controllers. It all depends upon the requirement of your project. For Demo purpose, I have created two separate controllers, one for creating a token and another one for validate. Have a look at below code.
RequestTokenController – To create a JWT and issue to those user whoever request with valid credentials.
using System.Net;
using System.Net.Http;
using System.Web.Http;
using WEBAPIJWT.Auth;
namespace WEBAPIJWT.Controllers
{
public class RequestTokenController : ApiController
{
public HttpResponseMessage Get(string username, string password)
{
if (CheckUser(username, password))
{
return Request.CreateResponse(HttpStatusCode.OK,
JwtAuthManager.GenerateJWTToken(username));
}
else
{
return Request.CreateResponse(HttpStatusCode.Unauthorized,
"Invalid Request");
}
}
public bool CheckUser(string username, string password)
{
// for demo purpose, I am simply checking username and password with predefined strings. you can have your own logic as per requirement.
if (username == "codeadda" && password == "abc123")
{
return true;
}
else
{
return false;
}
}
}
}
JwtAuthentication – It is used to at action level to protect it. It is only available when user request with validly issued JWT Token to that particular user.
using System.Web.Http;
using WEBAPIJWT.Auth;
namespace WEBAPIJWT.Controllers
{
public class ValuesController : ApiController
{
[JwtAuthentication]
public string Get()
{
return "Hello from Code-Adda.com";
}
}
}
view rawValuesController.cs hosted with ❤ by GitHub
Great. Now you have created your WEB API with JWT based authentication. You can use WEB API testing tools like Fiddler or Postman. Don’t worry we will guide you how to check. Here we are going to learn how to consume WEB API using postman. Follow given steps
Step 1: You have to enter a few details before you post details on the server.
  • Select type GET
  • Enter URL of WEB API with “/RequestToken” like “http://localhost:port/RequestToken”
  • Enter credential in Params { username and password }.
  • Click on the Send button.
Step 2: Once you get token, again you have to follow some step to authenticate generated token.
  • Select Type – GET
  • Enter WEB API URL with “/Values” in Params like “http://localhost:port/api/Values”
  • Enter Authorization for Key under Header and for Value, you have to enter “Bearer generated-token…” Or, Select authorization type – Bearer Token and Enter Token in Token field.
  • Click on the Send button
Once you click on the send button after entering all required field. you can see the output. If there is 200 Ok. Status which means you have successfully authenticated JSON Web Token and get back the result. In case if you have not provided valid token you will get an unauthorized error.
You can download complete source code from here – [su_button url=”https://github.com/raviranjankr/JWTWEBAPI” target=”blank” style=”3d” background=”#7a1d18″ size=”5″ radius=”round”]Download Source Code [/su_button]

No comments:

Post a Comment

Baisic Useful Git Commands

  Pushing a fresh repository Create a fresh repository(Any cloud repository). Open terminal (for mac ) and command (windows) and type the be...