ASP.NET 6 JWT Unauthorized Issue With Multiple Servers


Not long ago, my company upgraded to .NET Core and had some random authorization issues. Our general architecture is a load balancer that feeds a few API’s. After a user got logged in, he would immediately get logged out… Randomly.

This caused us to look at our login process. So, the user would login which calls an endpoint, and after that returned successfully, the system would then immediately call another endpoint to retrieve the user’s permissions. So, it was generally the second call that would fail with an Unauthorized (401) response.

On single server systems, this would never happen so it was not reproduceable locally (at least, not easily).

After a bit of searching, I figured out that the servers time’s were not in sync. Specifically, one of the server’s time was off by 10 seconds and that was the issue.

So, if the server that the user authenticates against is 10 seconds ahead of the other servers, when the user tried to retrieve the permission details using one of the other servers, the JWT’s start date was set in the future!

The first solution is to synch all servers time’s so they are always the same. Also, you can update the ClockSkew in the TokenValidationParameters class like so:

var jwtTokenValidationParameters = new TokenValidationParameters()
{
    ValidateIssuer = true,
    ValidIssuer = jwtBearerTokenSettings.Issuer,
    ValidateAudience = true,
    ValidAudience = jwtBearerTokenSettings.Audience,
    ValidateIssuerSigningKey = true,
    IssuerSigningKey = new SymmetricSecurityKey(key),
    ValidateLifetime = true,
    ClockSkew = TimeSpan.FromSeconds(60)
};

services.AddSingleton(jwtTokenValidationParameters);

services.AddAuthentication(options =>
{
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
    options.RequireHttpsMetadata = false;
    options.SaveToken = true;
    options.TokenValidationParameters = jwtTokenValidationParameters;
});

As you can see, I set the ClockSkew to 60 seconds which allows for a token to be plus or minus 60 seconds. Besides this, we manually synched the times for all of the servers. Finally, there are multiple programs that can sync windows server times (google search them).

This is all for this time, cya!

, ,