The JWT spec mentions a jti claim which allegedly can be used as a nonce to prevent replay attacks:

The "jti" (JWT ID) claim provides a unique identifier for the JWT. The identifier value MUST be assigned in a manner that ensures that there is a negligible probability that the same value will be accidentally assigned to a different data object; if the application uses multiple issuers, collisions MUST be prevented among values produced by different issuers as well. The "jti" claim can be used to prevent the JWT from being replayed. The "jti" value is a case-sensitive string. Use of this claim is OPTIONAL.

My question is, how would I go about implementing this? Do I need to store the previously used jtis and issue a new JWT with every request? If so, doesn't this defeat the purpose of JWTs? Why use a JWT instead of just storing a randomly-generated session ID in a database?

My REST API has a Mongo database and I'm not opposed to adding a Redis instance. Is there a better authentication option than JWT? I mainly just don't want to store passwords on the client which eliminates HTTP authentication as an option, however, as I'm getting deeper into this JWT stuff, I'm starting to feel as if a custom token implementation or different standard might better suit my needs. Are there any node/express packages for token based authentication that supports token revocation and rotating tokens?

Would appreciate any advice.


Indeed, storing all issued JWT IDs undermines the stateless nature of using JWTs. However, the purpose of JWT IDs is to be able to revoke previously-issued JWTs. This can most easily be achieved by blacklisting instead of whitelisting. If you've included the "exp" claim (you should), then you can eventually clean up blacklisted JWTs as they expire naturally. Of course you can implement other revocation options alongside (e.g. revoke all tokens of one client based on a combination of "iat" and "aud").


This is an old question, but I just worked on something similar. So I will share my thoughts here.

First of all, I agree that making database calls while validating JWT tokens undermines their primary advantage of being stateless.

None of the previous answers mention refresh tokens, but I believe they present a good trade-off between scalability and security.

In short, one can use regular auth tokens with a short expiration time (say, 15 minutes) and refresh tokens with long-lived access (say, 2 weeks). Whenever an auth token expires, the refresh token (stored more securely) is used to generate a new auth token without the user having to log in again.

The jti claim is best suited for refresh tokens. That gives you the ability to revoke access while minimizing the number of database calls made.

Let's say an average user session is 30 minutes. If you have a jti claim on regular auth tokens, then every API call is doing at least one extra database call to check if the token is not blacklisted. However, if you're only using a jti claim on refresh tokens, you will only make 2 database calls for authentication purposes during the course of a 30 minutes session (assuming each auth token expires after 15 minutes). That's a big difference.

Regarding implementation, you can use a randomly-generated UID and use it as your table's primary key. That guarantees the calls are as fast as possible. Moreover, you can add an expiration_time column with the same value as the exp claim. That way you can easily (batch) remove all the expired refresh tokens.

Why use a JWT instead of just storing a randomly-generated session ID in a database?

Or, if I may paraphrase, "why would you use a JWT refresh token rather than a random string saved on the database?"

I think you can do that, but using a JWT token has at least two advantages: (1) if the token is invalid or expired (when you decode it), you don't have to make any database calls at all. You just return a response with an error status code. (2) if you have a big system, you might be storing the "random strings" in different database tables based on some criteria (say, per client application [web vs mobile]). How would you know the table in which to look up the random string? With a JWT token, you can simply add a client_id claim. So, the ability to have information in the token is useful.


You can use express-jwt package

See express-jwt on GitHub or on NPM.

Express-jwt handles revoked tokens as described here: https://github.com/auth0/express-jwt#revoked-tokens

var jwt = require('express-jwt');
var data = require('./data');
var utilities = require('./utilities');

var isRevokedCallback = function(req, payload, done){
  var issuer = payload.iss;
  var tokenId = payload.jti;

  data.getRevokedToken(issuer, tokenId, function(err, token){
    if (err) { return done(err); }
    return done(null, !!token);
  });
};

app.get('/protected',
  jwt({secret: shhhhhhared-secret,
    isRevoked: isRevokedCallback}),
  function(req, res) {
    if (!req.user.admin) return res.send(401);
    res.send(200);
  });

You can also read part 4. How do we avoid adding overhead? from this oauth0 blog post.