JWT Authentication in .NET Core 2 Web Api with Custom Table

1 min read

In this article, we are going to secure our web api with token based authentication. You can download complete source code from git.

Problem Statement:

We chose .NET Core 2 for one of our recent projects. We wanted to implement JWT Authentication, found many articles on internet to achieve this but didn’t find any one using one’s own custom table. Most of them were using Identity’s default tables. If you are not familiar with JWT, read this intro.

We are using Entity Framework Core with Sql. If you want to MySql, you just have to use options.UseMySql instead of options.UseSql in ConfigureServices method of Startup.cs. See this in action here.

Use Cases:

  1. When a user logs in with valid credentials, a token is returned.
  2. When a user tries to access an action method decorated with [Authorize] with an invalid token or no token at all. It will return 401 Unauthorized status code.
  3. When a user tries to access an action whom access is only provided to admin(with a valid token though), it will return a 403 Forbidden status code.

We are going to skip the project creation, adding classes/dbContext for now, You can find complete source code on git.

Start by adding below code to your ConfigureServices method in Startup.cs class.

 

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
 .AddJwtBearer(options => {
  options.TokenValidationParameters = new TokenValidationParameters {
   ValidateIssuer = true,
    ValidateAudience = true,
    ValidateLifetime = true,
    ValidateIssuerSigningKey = true,
    ValidIssuer = Configuration.GetValue<string>("JwtIssuer"),
    ValidAudience = Configuration.GetValue<string>("JwtAudience"),
    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration.GetValue<string>("JwtSecretKey")))
  };
 });

Decorate your methods with [Authorize(Roles=`YourRole`)]

[Route("GetUser")]
[Authorize(Roles = "User, Admin")]
[HttpGet]
public async Task < IActionResult > GetUser() {
 return Ok(new CustomResponse < string > {
  Message = Global.ResponseMessages.Success,
  StatusCode = StatusCodes.Status200OK,
  Result = "You are an authorized user"
 });
}

Similarly decorate another action with [Authorize(Roles=`DifferentRole`)]

[Route("GetAdmin")]
[Authorize(Roles = "Admin")]
[HttpGet]
public async Task < IActionResult > GetAdmin() {
 return Ok(new CustomResponse < string > {
  Message = Global.ResponseMessages.Success,
  StatusCode = StatusCodes.Status200OK,
  Result = "You are an authorized admin"
 });
}

And in your login method,

[Route("LoginAsAdmin")]
[HttpGet]
public async Task LoginAsAdmin(string username, string password) {
 if (username == "Admin" & amp; & amp; password == "Pass") {
  var token = new JwtTokenBuilder()
   .AddSecurityKey(JwtSecurityKey.Create(_configuration.GetValue("JwtSecretKey")))
   .AddIssuer(_configuration.GetValue("JwtIssuer"))
   .AddAudience(_configuration.GetValue("JwtAudience"))
   .AddExpiry(1)
   .AddClaim("Name", "Admin")
   .AddRole("Admin")
   .Build();
  return Ok(new CustomResponse {
   Message = Global.ResponseMessages.Success, StatusCode = StatusCodes.Status200OK, Result = token.Value
  });
 } else
  return Ok(new CustomResponse {
   Message = Global.ResponseMessages.Forbidden, StatusCode = StatusCodes.Status403Forbidden, Result = new Error {
    ErrorMessage = Global.ResponseMessages.GenerateInvalid("username or password")
   }
  });
}

Notice that .AddClaim and .AddRole methods are defined in a helper class.

That’s it, you can test the uses cases stated above by using postman. Moreover, swagger is also integrated, you can download complete source code from GitHub. Your valuable feedback is highly appreciated.

Thanks!

Thanks for reading. If you enjoyed this article, feel free to hit that clap button 👏 to help others find it.

Leave a Reply

Your email address will not be published. Required fields are marked *