Page Contents
Since the token is signed with a public/private key pairs, the signature certifies that only the party holding the private key is the one that signed it. So this way authentication is done by JWT mechanism.
This tutorial is a part of series called JSON Web Token (JWT) in ASP.NET Core. There are 2 tutorials to master it:
There are 2 projects for doing this JWT implementation, they are built in ASP.NET Core 3.1. These projects are described below:
1. The JWTAPI project that returns a set of flight reservations in JSON format to the client. This project will validate the JWT token in order to authenticate the client requests.
2. The JWTClient project from where the API requests are made. This project will first create the JWT Token and then adds it to the HTTP’s Authorization header, and then consumes the API.
Finally click the create button to create this project.
services.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(options => { options.SaveToken = true; options.RequireHttpsMetadata = false; options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters() { ValidateIssuer = true, ValidateAudience = true, ValidAudience = "https://www.yogihosting.com", ValidIssuer = "https://www.yogihosting.com", IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("MynameisJamesBond007")) }; });Explanation: The ‘AuthenticationOption’ has 3 properties – DefaultAuthenticateScheme DefaultChallengeScheme and DefaultScheme. These 3 are set to the default value of the AuthenticationScheme property in the JwtBearerAuthenticationOptions object, by the way this is Bearer. Next, use the AddJwtBearer() method to configure the ‘JwtBearerOptions’ like this:
.AddJwtBearer(options => { options.SaveToken = true; options.RequireHttpsMetadata = false; options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters() { ValidateIssuer = true, ValidateAudience = true, ValidAudience = "https://www.yogihosting.com", ValidIssuer = "https://www.yogihosting.com", IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("MynameisJamesBond007")) }; });
I used the TokenValidationParameters property to specify how to token will be validated on the server. For this I set values for the ‘Issuer’ and ‘Audience’.
The most important property here is the IssuerSigningKey that is used to set the security key. Through this key the token is signed by the client using JWT way. The server also uses it to validate the token which it gets from the client request.
I am using ‘MynameisJamesBond007’ as my security key, you can use any key you want (min 16 characters in length).
Next, go to the Configure() method and tell your app to use authentication and authorization. You add the below to lines of code after the app.UseRouting().
app.UseAuthentication();
app.UseAuthorization();
public class Reservation { public int Id { get; set; } public string Name { get; set; } public string StartLocation { get; set; } public string EndLocation { get; set; } }
Next, create a new controller called ReservationController.cs. This controller will have the task to return reservations to the client whenever request to the API is made by the client.
The full code of this controller is given below:
[Route("[controller]")] [Authorize] public class ReservationController : Controller { [HttpGet] public IEnumerable<Reservation> Get() => CreateDummyReservations(); public List<Reservation> CreateDummyReservations() { List<Reservation> rList = new List<Reservation> { new Reservation {Id=1, Name = "Ankit", StartLocation = "New York", EndLocation="Beijing" }, new Reservation {Id=2, Name = "Bobby", StartLocation = "New Jersey", EndLocation="Boston" }, new Reservation {Id=3, Name = "Jacky", StartLocation = "London", EndLocation="Paris" } }; return rList; } }
Explanation : I have marked this controller with [Authorize] attribute of the Microsoft.AspNetCore.Authorization namespace. This is done specifically in order to secure the API with JWT token. I will tell more about it later on.
I have created some dummy reservations inside the CreateDummyReservations () function and these are returned by the API in JSON. The HttpGet method of the API does this work of returning JSON data of reservations:
[HttpGet] public IEnumerable<Reservation> Get() => CreateDummyReservations();Congratulations: You have successfully secured your API with JWT. Now request from the clients will be authenticated beforehand and then the API will provide them with data.
When the browser starts, open the URL of the ‘ReservationController’ which in my case is:
https://localhost:44314/Reservation
You will see the JSON containing the reservations as shown below:
Next, I will create a client project from where JWT bearer token will be created and added to the HTTP Authorization Header, and then API is called for.
Like what you did before, create a new ASP.NET Core Web Application and name it ‘JWTClient’.
Next, select ASP.NET Core 3.1 framework from the dropdown, and then select the template that says Web Application (Model-View-Controller). Click the create button to create this project.
public class Reservation { public int Id { get; set; } public string Name { get; set; } public string StartLocation { get; set; } public string EndLocation { get; set; } }
The code of this action method is given below:
[HttpPost] public async Task<IActionResult> Index(string username, string password) { if ((username != "Secret") || (password != "Secret")) return View((object)"Wrong Username or Password"); var tokenString = GenerateJSONWebToken(); List<Reservation> reservationList = new List<Reservation>(); using (var httpClient = new HttpClient()) { httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokenString); using (var response = await httpClient.GetAsync("https://localhost:44314/Reservation")) { string apiResponse = await response.Content.ReadAsStringAsync(); reservationList = JsonConvert.DeserializeObject<List<Reservation>>(apiResponse); } } return View("Reservation", reservationList); } private string GenerateJSONWebToken() { var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("MynameisJamesBond007")); var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256); var token = new JwtSecurityToken( issuer: "https://www.yogihosting.com", audience: "https://www.yogihosting.com", expires: DateTime.Now.AddHours(3), signingCredentials: credentials ); return new JwtSecurityTokenHandler().WriteToken(token); }
if ((username != "Secret") || (password != "Secret"))
return View((object)"Wrong Username or Password");
When the credentials are correct then the GenerateJSONWebToken() function is called where the JWT Token is created by assigning values to the issuer, audience, expires and signingCredentials properties of the JwtSecurityToken class, see the below code where I am doing all these things:
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("MynameisJamesBond007")); var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256); var token = new JwtSecurityToken( issuer: "https://www.yogihosting.com", audience: "https://www.yogihosting.com", expires: DateTime.Now.AddHours(3), signingCredentials: credentials ); return new JwtSecurityTokenHandler().WriteToken(token);
You could see I am using my security key which is ‘MynameisJamesBond007’ and Security Algorithm called HmacSha256 to create this token.
The JWT Token is returned by the GenerateJSONWebToken() function and the variable ‘tokenString’ stores it.
Next, I create the HttpClient class object and I adds the Jwt Token to the HTTP authorization header like this:
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokenString);
And finally make the API call to the URL – https://localhost:44314/Reservation as shown below:
using (var response = await httpClient.GetAsync("https://localhost:44314/Reservation")) { string apiResponse = await response.Content.ReadAsStringAsync(); reservationList = JsonConvert.DeserializeObject<List<Reservation>>(apiResponse); }
I will need 2 views, the first one is the ‘Index’ View kept inside the ‘Views/CallAPI’ folder. The ‘Index’ view code is given below:
@model string <h2>Login</h2> @{ if (Model != null) { <div class="alert alert-danger">@Model</div> } } <form method="post"> <table class="w-25 table table-striped table-bordered"> <tbody> <tr> <td>Username</td> <td><input type="text" name="username" /></td> </tr> <tr> <td>Password</td> <td><input type="text" name="password" /></td> </tr> <tr> <td colspan="2"> <button>Submit</button> </td> </tr> </tbody> </table> </form>
The second view is the ‘Reservation’ view which is also kept inside the ‘Views/CallAPI’ folder. It’s code is given below:
@model IEnumerable<Reservation> @{ ViewBag.Title = "All Reservations";} <h2>All Reservations</h2> <table class="table table-sm table-striped table-bordered m-2"> <thead><tr><th>ID</th><th>Name</th><th>Start Location</th><th>End Location</th></tr></thead> <tbody> @foreach (var r in Model) { <tr> <td>@r.Id</td> <td>@r.Name</td> <td>@r.StartLocation</td> <td>@r.EndLocation</td> </tr> } </tbody> </table>
Congratulations, your API consuming code is complete. It’s now time to test it.
Coming to the testing part, make sure you run your JWTAPI project so that you can consume your API. Next run your JWTClient project and go to the ‘CallAPI’ controller’s URL which in my case is ‘https://localhost:44361/CallAPI’
First you see the login screen where you enter both username and passwords as ‘Secret’.
Next, click the ‘Submit’ button, which will make the API call and show all the flight reservations. Check the below image:
You can download the full codes of this tutorial from the below link:
DownloadJWT Claims are pieces of information added to the token. For example, a JWT token may contain a claim called Name that asserts that the name of the user authenticating is “Bobby”.
Let me show you how to do this thing. Go to the client project and inside the GenerateJSONWebToken() function create a claim and add it to the token as shown below:
private string GenerateJSONWebToken() { var claims = new[] { new Claim("Name", "Bobby"), new Claim(JwtRegisteredClaimNames.Email, "[email protected]"), }; //… var token = new JwtSecurityToken( issuer: "https://www.yogihosting.com", audience: "https://www.yogihosting.com", expires: DateTime.Now.AddHours(3), signingCredentials: credentials, claims: claims ); return new JwtSecurityTokenHandler().WriteToken(token); }
Next, I use this ‘Name’ claim value to filter out my flight reservations. So update the API to fetch this claim’s value through the HttpContext.User.Claims class, and then filter out the reservation so that reservation’s name matches exactly to the ‘Name’ value assigned on the claim.
The updates code which does this work is shown below:
[HttpGet] public IEnumerable<Reservation> Get() { var claims = HttpContext.User.Claims; return CreateDummyReservations().Where(t => t.Name == claims.FirstOrDefault(c => c.Type == "Name").Value); }
I have created a small video to show this working:
Hi i would be really interesting in an article with these features:
– A secured webapi (project): ASP.NET WebApi (net core 3.1) with JWT authentication / autorization an roles.
– A secured client (project): ASP.NET MVC Core 3.1 application with his own authentication and roles, which invokes the secured webapi.
– The secured client, should invoke the secured webapi, generate token and refresh tokens.
I could make a small donation if you provide a example / solution with those requirements. Pleas let me know if possible.
Hello Eduardo, Right now I don’t have any project which does this work. You can download the source code of this tutorial and will have to add these features by your own. Check the JWT authentication docs to get more info on them. Slowly and steadily you will be able to create all these features by your own.
Thank you.