I'm building a .NET Core API. I've created a simple ReactJS application that consumes our API, and we're using JWT tokens for authentication. When validating a request, the client sends a token to the server. Now, when I call logout and then log back in again, the client is sent a new token. What about the previous one? How can I delete my previous JWT token? If you're looking for answers to these questions, you've come to the right place. Let's discuss the solution.

we can force a logout or expiration of a JWT token by implementing certain strategies on the server side. Here are some common approaches along with code examples:

  1. Short Token Expiry: Set a short expiry time for JWT tokens. For example, in ASP.NET Core, we can configure token expiration in the authentication middleware:
  2.     services.AddAuthentication(options =>
        {
            options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        })
        .AddJwtBearer(options =>
        {
            options.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuer = true,
                ValidateAudience = true,
                ValidateLifetime = true,
                ValidateIssuerSigningKey = true,
                ValidIssuer = "",
                ValidAudience = "",
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("your_secret_key")),
                ClockSkew = TimeSpan.Zero, 
                RequireExpirationTime = true, 
                ExpireTimeSpan = TimeSpan.FromMinutes(10) // Set token expiry to 10 minutes
            };
        });
        
  3. Blacklisting Tokens: We can maintain a blacklist of expired or invalidated tokens on the server.This code provides a way to blacklist tokens by adding them to a HashSet _blacklistedTokens using the BlacklistToken method, and then checking if a token is blacklisted using the IsTokenBlacklisted method , this can be useful in scenarios where certain tokens need to be restricted from certain actions or accesses within an application. Here's a simple example of how you can implement token blacklisting in ASP.NET Core using a HashSet:
  4.     private static HashSet _blacklistedTokens = new HashSet();
    
        // Method to blacklist a token
        public void BlacklistToken(string token)
        {
            _blacklistedTokens.Add(token);
        }
    
        // Method to check if a token is blacklisted
        public bool IsTokenBlacklisted(string token)
        {
            return _blacklistedTokens.Contains(token);
        }
        
  5. Revoke Tokens: We can also implement a mechanism for users to revoke their tokens. Action receives a request to revoke a token, extracts the token from the request body, invokes a method to revoke the token which should be implemented like in _tokenService, and then returns a response indicating the success of the operation.Below is the example code of how we can create an API endpoint for token revocation in ASP.NET Core:
  6.     [HttpPost]
        [Route("revoke-token")]
        public IActionResult RevokeToken([FromBody] RevokeTokenRequest model)
        {
            //logic to revoke token
            _tokenService.RevokeToken(model.Token);
            return Ok(new { message = "Token revoked successfully" });
        }
        
    public class TokenService
    {
        private readonly HashSet<string> _blacklistedTokens;
    
        public TokenService()
        {
            _blacklistedTokens = new HashSet<string>();
        }
    
        public void RevokeToken(string token)
        {
            // Add the token to the blacklist
            _blacklistedTokens.Add(token);
        }
    
        public bool IsTokenRevoked(string token)
        {
            // Check if the token is in the blacklist
            return _blacklistedTokens.Contains(token);
        }
    }
    
  7. Change Token Signature: By change the token signing key periodically to invalidate existing tokens. Below code provided shows the approach of changing the token signature periodically to invalidate existing tokens.
  8.     // Generate a new signing key
        var newSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("new_secret_key"));
    
        // Update token validation parameters with the new signing key
        options.TokenValidationParameters.IssuerSigningKey = newSigningKey;
        

By implementing one or a combination of these strategies, we can effectively force a logout or expiration of JWT tokens in our application.

2

Actually, the best way to handle logout in JWT-based authentication is by removing the token from the client. We can achieve this by setting a short lifetime for tokens (around 5-10 minutes) and implementing refresh tokens for additional security.

In this approach, there's less chance for attackers to manipulate the JWT. Once a JWT is generated and sent to the client, it cannot be altered directly by the client. Instead, the client must go through the backend to obtain a new token.

To invalidate or revoke a JWT, we can utilize a Redis (recommended) or database to store invalidated JTI (Token ID) associated with each JWT issued.

If we opt not to use Redis or a database, we can still maintain security by keeping the JWT lifetime short, such as 10 minutes then, during logout, we remove the token from the client side  However, it's important to note that this approach doesn't immediately invalidate the JWT. Clients may still access the API if they retain their token before it's removed.

By using short-lived JWTs and refresh tokens, we enhance security while still providing a user experience.