Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Could we destroy/invalidate JWT token in Asp.NET Core?

I use ASP.NET Core & ASP.NET core Identity to generate a JWT token.

On the client-side, my React (SPA) app calls API to create the token then include Authorization: Bearer token from API in subrequests.

When I want to logout, how can I immediately invalidate the token on the server-side?

Currently, I just delete the bear token on the client-side and not included in the next request?

Reference: https://blogs.msdn.microsoft.com/webdev/2017/04/06/jwt-validation-and-authorization-in-asp-net-core/


Code in Configure section in Startup.cs

app.UseJwtBearerAuthentication(new JwtBearerOptions
{
    AutomaticAuthenticate = true,
    AutomaticChallenge = true,
    TokenValidationParameters = new TokenValidationParameters
    {
        ValidIssuer = "MySite",
        ValidAudience = "MySite",
        ValidateIssuerSigningKey = true,
        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("VERYL0NGKEYV@LUETH@TISSECURE")),
        ValidateLifetime = true
    }
});

API to create a token

[HttpPost("Token")]
public async Task<IActionResult> CreateToken([FromBody] LoginModel model)
{
    try
    {
        var user = await userManager.FindByNameAsync(model.Email);
        if (passwordHasher.VerifyHashedPassword(user, user.PasswordHash, model.Password) == PasswordVerificationResult.Success)
        {

            var claims = new[]
            {
                new Claim(JwtRegisteredClaimNames.Sub, user.UserName),
                new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
                new Claim(JwtRegisteredClaimNames.Email, user.Email)
            };

            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("VERYL0NGKEYV@LUETH@TISSECURE"));
            var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
            var token = new JwtSecurityToken(
                "MySite",
                "MySite",
                claims,
                expires: DateTime.UtcNow.AddMinutes(45),
                signingCredentials: creds);

            return Ok(new
            {
                Token = new JwtSecurityTokenHandler().WriteToken(token),
                Expiration = token.ValidTo,
            });
        }
        return BadRequest();
    }
    catch (Exception ex)
    {
        logger.LogError(ex.ToString());
        return StatusCode((int)HttpStatusCode.InternalServerError);
    }
}
like image 726
Hung Quach Avatar asked Aug 18 '17 04:08

Hung Quach


People also ask

Can we destroy JWT token?

Actually, JWT serves a different purpose than a session and it is not possible to forcefully delete or invalidate an existing token.

How do you destroy old JWT tokens?

On the client side, delete the cookie from the browser using javascript. On the server side, set the cookie value to an empty string or something useless (for example "deleted" ), and set the cookie expiration time to a time in the past. On the server side, update the refreshtoken stored in your database.

Can JWTs be stolen?

The token can be used to access the applicationIf your JWT is stolen or compromised, then the attacker has full access to your account. The attacker can send requests to applications, pretending to be you, and can make potentially harmful changes.

Should JWT tokens be invalidated on the server after logout?

While doing that server would be able to close all the user sessions but it won't be able to invalidate the JWT token as it's stateless and an immutable object. This can quickly become a problem - when a user logs out, the JWT token has to be invalidated for further use.


1 Answers

You can't easily have it expire, w/o losing some of the advantages of it or making the solution significantly more complex.

Best bet is to make the access token time short enough (<= 5 mins) and the refresh token long running.

But if you really want to invalidate it immediately, you would need a few things:

  1. Cache the token's ID once the token is created with a duration as long as the expiration time of the token (both, access and refresh token)
  2. [If Farm/multiple instances]You need to cache it in a distributed cache, like redis
  3. [If Farm/multiple instances]You need to propagate it via message bus (i.e. using Redis, RabbitMQ or Azure Message Bus) to every instance of your application, so they can store it in a local memory cache (so you don't have to have a network call, each time you want to validate it)
  4. During authorization, you need to validate if the ID is still inside the cache; if not, refuse authorization (401)
  5. When user logs out, you need to remove your item from the cache.
  6. [If Farm/multiple instances]Remove the item from the distributed cache and send a message to all instances so they can remove it from their local cache

Other solutions not requiring message bus/distributable cache would require to contact the auth server on every single request, killing the main advantage of an JWT token.

The main advantage of JWT is that they are self-contained and a web service do not have to call another service to validate it. It can be validated locally by validating the signature (since the token can't be changed by the user w/o invalidating the signature) and expiration time/audience the token is meant for.

like image 98
Tseng Avatar answered Sep 16 '22 17:09

Tseng