How to use jti claim in a JWT
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.
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.