6
votes

Currently I am programming a ASP.NET-Core WebApi using JWT-Bearer-Authentication.

To make the API accessible from different timezones I am using the following Pattern to set the fields nbf (notBefore) and exp (expires) inside my JWT to a UTC-Timestamp:

var utcNow = DateTime.SpecifyKind(DateTime.UtcNow, DateTimeKind.Unspecified);

...

var tokenOptions = new JwtSecurityToken(
                notBefore: utcNow,
                expires: utcNow.AddSeconds(3600),
            );
...

For token generation, everythings works pretty good, nbf and exp contain a UNIX-Timestamp representing the current UTC-Time.

But when doing token validation, everything works for 5 Minutes (my clock-skew setting) and then I only get 401 from API, because the token-validation is done with my current timezone here in Germany.

Is there a way to setup the JwtAuthentication-Middleware in .NET-Core to use UTC-Time for token-validation? Or are there any other ways to solve this?

3
Did you got the solution?Chandan Y S

3 Answers

2
votes

One solution is to validate the token without expiration time. This will return valid token even if the token had expired. Then in your code manually check the tokens expiration time. Here are snippets of the codes:

var validationParameters = new TokenValidationParameters()
{
   RequireExpirationTime = false,  // we can check manually
   ValidateIssuer = true,
   ValidateAudience = true,

   .
   .
   IssuerSigningKey = new SymmetricSecurityKey(symmetricKey)
};

Then when token is validated, check the expiration time with:

public bool IsExpired(DateTime now)
{
    return JwtSecurityToken.ValidTo > now;
}

I hope this answer will help someone.

2
votes

For a more complete answer, in your Startup.cs:

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearer(options =>
        {
            options.TokenValidationParameters = new TokenValidationParameters
            {
                // ...
                ValidateLifetime = true,
                LifetimeValidator = (DateTime? notBefore, DateTime? expires, SecurityToken securityToken, 
                                     TokenValidationParameters validationParameters) => 
                {
                    return notBefore <= DateTime.UtcNow &&
                           expires >= DateTime.UtcNow;
                }
            };
        });
1
votes

It's already the case. The System.IdentityModel.Tokens.Jwt package does indeed validate JWT lifetime against UTC time. Here's the relevant bit from the source:

public static void ValidateLifetime(DateTime? notBefore, DateTime? expires, SecurityToken securityToken, TokenValidationParameters validationParameters)
        {
            ...

            if (notBefore.HasValue && expires.HasValue && (notBefore.Value > expires.Value))
                throw LogHelper.LogExceptionMessage(new SecurityTokenInvalidLifetimeException(LogHelper.FormatInvariant(LogMessages.IDX10224, notBefore.Value, expires.Value))
                { NotBefore = notBefore, Expires = expires });

            DateTime utcNow = DateTime.UtcNow;
            if (notBefore.HasValue && (notBefore.Value > DateTimeUtil.Add(utcNow, validationParameters.ClockSkew)))
                throw LogHelper.LogExceptionMessage(new SecurityTokenNotYetValidException(LogHelper.FormatInvariant(LogMessages.IDX10222, notBefore.Value, utcNow))
                    { NotBefore = notBefore.Value });
 
            if (expires.HasValue && (expires.Value < DateTimeUtil.Add(utcNow, validationParameters.ClockSkew.Negate())))
                throw LogHelper.LogExceptionMessage(new SecurityTokenExpiredException(LogHelper.FormatInvariant(LogMessages.IDX10223, expires.Value, utcNow))
                    { Expires = expires.Value });

            // if it reaches here, that means lifetime of the token is valid
            LogHelper.LogInformation(LogMessages.IDX10239);
        }

https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/blob/b5b7ed8fb8ce513469b51b87c5f76314783b74e3/src/Microsoft.IdentityModel.Tokens/Validators.cs#L268