I am trying to implement Token Based Authentication through refresh tokens and JWT in .NET Core 2.1.
This is how I am implementing the JWT Token:
Startup.cs
services.AddAuthentication(option => { option.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; option.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; option.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; }).AddJwtBearer(options => { options.SaveToken = true; options.RequireHttpsMetadata = true; options.TokenValidationParameters = new TokenValidationParameters() { ValidateIssuer = true, ValidateAudience = true, ValidAudience = Configuration["Jwt:Site"], ValidIssuer = Configuration["Jwt:Site"], IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:SigningKey"])) }; options.Events = new JwtBearerEvents { OnAuthenticationFailed = context => { if (context.Exception.GetType() == typeof(SecurityTokenExpiredException)) { context.Response.Headers.Add("Token-Expired", "true"); } return Task.CompletedTask; } }; });Token Generation:
var jwt = new JwtSecurityToken( issuer: _configuration["Jwt:Site"], audience: _configuration["Jwt:Site"], expires: DateTime.UtcNow.AddMinutes(1), signingCredentials: new SigningCredentials(signinKey, SecurityAlgorithms.HmacSha256) ); return new TokenReturnViewModel() { token = new JwtSecurityTokenHandler().WriteToken(jwt), expiration = jwt.ValidTo, currentTime = DateTime.UtcNow };I am getting he correct values in Response.
But after a minute I set the same token for authorization in Postman and it works. If the token has expired it shouldn't.
I am using bearer tokens as authentication.
What am I doing wrong? Need direction.
31 Answer
There is a token validation parameter called ClockSkew, it gets or sets the clock skew to apply when validating a time. The default value of ClockSkew is 5 minutes. That means if you haven't set it, your token will be still valid for up to 5 minutes.
If you want to expire your token on the exact time; you'd need to set ClockSkew to zero as follows,
options.TokenValidationParameters = new TokenValidationParameters()
{ //other settings ClockSkew = TimeSpan.Zero
};Another way, create custom AuthorizationFilter and check it manually.
var principal = ApiTokenHelper.GetPrincipalFromToken(token);
var expClaim = principal.Claims.First(x => x.Type == "exp").Value;
var tokenExpiryTime = Convert.ToDouble(expClaim).UnixTimeStampToDateTime();
if (tokenExpiryTime < DateTime.UtcNow)
{ //return token expired
} Here, GetPrincipalFromToken is a custom method of the ApiTokenHelper class, and it will return the ClaimsPrincipal value that you've stored while issuing a token.