How to use jti claim in a JWT

2019-03-08 05:39发布

问题:

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.

回答1:

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").



回答2:

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.