JWT Authentication with .Net Core

credit: Orlando Florin Rosu – Dreamstime.com

So we want to secure our API layer right? we want to write something in one place that will take care of our authentication.

You can use a bearer token and validate each incoming request using a database lookup costly), or you can use JWT token. I like JWT because JWT can store any type of data, which is where it excels in combination with OAuth. With a JWT access token, you need far less database lookups while still not compromising security. You can also can add additional information that will help you avoid database lookups and just pull it from the token.

So here is how a JWT looks like

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ0ZXN0MyIsInVzZXJuYW1lIjoidGVzdDMiLCJ0bWlkIjoiYTA0MzdjYzQtOGQ0MS00YWE5LTk4ZjAtMmIwMjE4NzJmMjdhIiwidWlkIjoiMzkwZGNkMDMtYzgwMC00YTQ1LTVlMmItMDhkNzViZDNhOTZjIiwiZGlzcGxheSI6IlRlc3QgVXNlciIsInJvbGUiOiJBZG1pbiIsImp0aSI6Im15VG9rZW4tNjFjYjNmMWMtNjY2Yy00MTg0LTlmNGMtYTAxMjIxNWNmNDBkIiwibmJmIjoxNTcyMzg2NjYwLCJleHAiOjE1NzI0MDEwNjAsImlhdCI6MTU3MjM4NjY2MCwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo2MTEwMy8iLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjYxMTAzLyJ9.bSGhYLOcBR3kwxBAzF4kNme5ZJ3fI9qfJdMsyqHm7d0

And if you take this exact token and paste it on https://jwt.io/ you will see:

You can see on the right side that we can see all the claims (the data) on that token. So in this example, I have my display string for that user, and that saves me database lookups.

The reason we can avoid database lookups, is because JWT contains a base64 encoded version of the data you need to determine the identity and scope of access. When we generate the token, we use a signature (a secret). when reading the token, we must use the same secret. This comparison is way faster than accessing the database to check that the token exists.

Since we don’t have database lookups, we cannot revoke a token. A token is valid until it expires. Hence it is a good idea to have short expiration time for tokens. If you must be able to revoke a token immediately, this is not the best solution for you. It all depends on the system you are working on.

So now that we know what and why to use JWT token. Let’s see how to use it in .Net Core.

In your Startup.cs you will need to add:

public void AddAuthentication(IServiceCollection services)
    {          
        services.AddAuthentication(option =>
        {
            option.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            option.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            option.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
        }
          ).AddJwtBearer(options => { 
              options.RequireHttpsMetadata = true;
              options.TokenValidationParameters = JWTConfigurationProvider.TokenValidationParameters(Configuration);
          });
    }

And some code to get the TokenValidationParameters

private static TokenValidationParameters GetTokenValidationParameters(IConfiguration config)
        {
            return new TokenValidationParameters
            {
                AuthenticationType = AuthenticationType,
                ValidateLifetime = true,
                ValidateIssuer = true,
                ValidateAudience = true,
                ValidAudience = Audience(config),
                ValidIssuer = Issuer(config),
                IssuerSigningKey = SymmetricSecurityKey(config,"SigningKey")
            };
        } 

And now we need to add the Authorize attribute on our controller (or routes):

     [Authorize]
     [Route("api/users")]
     [Produces("application/json")]
     public class UsersController : Controller
     {}

And now, every incoming call will be checked if allowed. meaning if the incoming token is what we expect and if still valid.

So how does it work with a client? First off we need to sign in to get a token. That route should not have the Authorize attribute since the user is not logged in yet.

We just call our route with the username and password AND with Basic Auth

The response will be the JWT token from the server.

On our next calls, we need to use that token by using Bearer Token as the type

Since our token expiration time is short, we need to expose a refresh token route. we can use a different route, or just use the same route that can accept both Basic (for the first time the user logs in) and Bearer (for refresh token).

Here is my route to get a token

You can s

[HttpPost]
 [BasicAuthentication]
 [ProducesResponseType(typeof(string), StatusCodes.Status200OK)]
 [ProducesResponseType(typeof(List), StatusCodes.Status400BadRequest)]
 [ProducesResponseType(typeof(List), StatusCodes.Status500InternalServerError)]
 public async Task Post()
 {
     string token = null;
     if (User.Identity.AuthenticationType == Core.Security.JWTConfigurationProvider.AuthenticationType)
     {
         var username = (User.Identity as ClaimsIdentity)?.FindFirst(Core.Security.ClaimTypes.Username)?.Value;
         if (username != null)
         {
             var roleClaim = (User.Identity as ClaimsIdentity)?.FindFirst(ClaimTypes.Role)?.Value;
             UserRole role = (UserRole)Enum.Parse(typeof(UserRole), roleClaim);
             token = await _service.GetTokenAsync(username, role);
         }
    }
 if (User.Identity.AuthenticationType == "Basic")
 {
     var username = (User.Identity as ClaimsIdentity)?.FindFirst(Core.Security.ClaimTypes.Username).Value;
     var password = (User.Identity as ClaimsIdentity)?.FindFirst(Core.Security.ClaimTypes.Password).Value;
     token = await _service.GetTokenAsync(username, password);
 }
 if (token.IsEmpty())
     return Unauthorized();
 return Ok(token);
}

You can see that the same route can handle both authentication methods. but how?

The key is adding my own custom BasicAuthenticationAttribute

public class BasicAuthenticationAttribute : AuthorizeAttribute, IAsyncAuthorizationFilter
     {
         public async Task OnAuthorizationAsync(AuthorizationFilterContext authorizationFilterContext)
         {
             await Task.Run(() => Authenticate(authorizationFilterContext));
         }
         private void Authenticate(AuthorizationFilterContext authorizationFilterContext)
         {
             var context = authorizationFilterContext.HttpContext;
             var authHeader = context.Request.Headers["Authorization"][0];
if (authHeader == null || !authHeader.StartsWith("basic", StringComparison.OrdinalIgnoreCase))
        {
            return;
        }

        var token = authHeader.Substring("Basic ".Length).Trim();

        var credentialstring = Encoding.UTF8.GetString(Convert.FromBase64String(token));
        var credentials = credentialstring.Split(':');

        if (credentials.Length < 2)
        {
            authorizationFilterContext.Result = new UnauthorizedResult();
            return;
        }

        var claims = new List
            {
                new Claim(Core.Security.ClaimTypes.Username, credentials[0]),
                new Claim(Core.Security.ClaimTypes.Password, credentials[1])
            };
        var identity = new ClaimsIdentity(claims, "Basic");

        authorizationFilterContext.HttpContext.User = new ClaimsPrincipal(identity);
    }
}

This customer ”’AuthorizeAttribute”’ is reading the token. If the incoming token is Basic (meaning this is the initial log in), we pull the username and password and build a ClaimIdentity with those values.

If it is a JWT token, we do nothing and move on to the controller.

And as we saw before, the controller route is checking which authentication type is coming. If it is a JWT, it means we need to refresh the token (create a new token). If it is a basic type, we need to check that the username and password are valid and create the token.

So now we have one route to handle both refresh and create tokens. Sweet!

My thoughts about microservices

credit: Publicdomainphotos – Dreamstime.com

Based on my personal experience, here is why I like microservice architecture :

  • Independent Development:
    • Different teams can own small pieces of code. Even within the same team, different developers can work on different services and not step on each other’s toes (no more merge conflicts!)
    • We can use different technology stacks. we can use NoSql database for one service and a relational database for another service. we can write one service in .Net and one service in Java if we really want to.
    • What I have also seen is that it’s easier to follow the single responsibility pattern and avoid ‘god’ objects. Developers sometimes tend to add things to existing component, leading to mega classes that are doing way too much. In microservices architecture, it is harder to do so because of that separation. you end up with smaller and simpler components which is great.
  • Independent Deployment:
    • We can deploy only parts of our system. We don’t need to wait for an entire feature to be complete.
    • It also means we can replace services very easily. if we found a bug in our Ordering system, we can just fix it and deploy it without the need to deploy the rest of our services.
    • We have more control about what, when and where to deploy. We might want to deploy different versions to different regions in the world.
  • Independent Scalability: services can be scaled independently of each other whenever there is a need like a really busy period (think about retail stores on black Friday for example)
  • Application agnostic: You can write a service that can be used by more than one team. For example; I wrote an Email Service that is responsible for sending emails. Now if the company has multiple products, they can all use that service.

Based on my personal experience, here are reason to not like microservice architecture:

  • Might be harder to develop locally:
    • You might need to have multiple IDEs or processes running locally in order to run a simple business scenario. that can slow things down and make it more complicated to debug.
    • harder to have good integration tests.
  • Could increase DevOps complexity: a good DevOps team should be ready to handle any amount of services, but easier said than done. The more moving parts you have, the more you’d need to communicate,synch and even monitor.
  • Adding complexity:
    • Version control can be hard to control, maintain and support.
    • May end up with complex spaghetti code:
      not good old spaghetti code, but a micro-service spaghetti code. What I mean is that you might have X amount of services calling other services. This could really be a problem without defined boundaries (where do we split services?).
    • Distributed Transactions and consistency across microservices: In a monolithic system, we have a database system to ensure ACIDity. So in a good old monolith, we can easily rollback the entire transaction if something failed. But in distribute systems it can very hard. One way to solve it is by having idempotent services but that’s not always an option. we sometimes must have success/fail state of the entire transaction. There are ways to deal with it, but it’s just adding more complexity when you compare it to a simple one transaction in a monolith system.

Final thought about microservice architecture :

  • Use it when it makes sense. Don’t just go with it because it’s a hot trend. some solutions might be fine with a decent size monolith.
  • If you choose to go with it, try to have defined boundaries. it can be hard and usually it’s a task for a senior team member that has some business knowledge. I have seen super small microservices that were really nano-services; so small that I could barely see the benefit of splitting them and the overhead was bigger than the benefit of having them.

Microwave awful state machine

The ‘End’ state in my amazing microwave

I have an old microwave. probably 20 years old.

It is working just fine, but I do have one complaint.

This microwave has an awful design flaw; after it’s done heating, it goes to ‘End’ state.

So what is the big deal with that? at that point you must click the ‘clear/off’ button if you want to run it again. You would expect that after it reaches that ‘end’ state, the user would be able to use it again as normal without the need to press a button to go to the ‘ready’ state.

I know it’s a first world problem but I thought it is a good example of a really bad design decision. The truth is that today even one extra click is not something we tolerate.