JSON Web Tokens on Rails

Zane Wolfgang Pickett
3 min readJan 20, 2016

--

A couple of weeks ago on a personal project, David Rivera introduced me to JSON Web Tokens or JWTs. If you’re not already familiar with JWTs, are a signed JSON session store that the client keeps. The token allows us to do a few things, including SSO in a pretty elegant way. I highly recommend checking out jwt.io for more in-depth details.

One of the nice things about JWTs is since you can inherently trust them, due to the signature, is that you can store certain user details and permissions to be used by the session. Both the front-end web-app and the backend API complete individual authenticated actions without having to hit the datastore to reverify the session each time.

However this presents a problem, JWTs are valid as long as they have not expired. You could have short expirations, and rotate your tokens a lot, but that largely negate the performance gain and would force users to sign in again if they idle too long. Which would be great if this were a bank or something else that needed a high level of security.

You could attempt to store a whitelist, but then you are just effectively reimplementing session storage the old way and having all that same overhead. Including the fact that the whitelist will grow with every user and session created.

The solution that David came up with was to store a blacklist of token ids(JTI) in Redis and make sure only to check that after you have validated the token. If a token is invalid, like when it is expired, you don’t need to incur the blacklist check overhead. The Redis storage is completed using the expire feature, meaning that it will auto clean up after a revoked token would have normally expired. We can then store and check against the smallest possible list, making it as fast and cheap as possible.

I have noticed that it is becoming common to give your token expiry a bit of leeway, so that you can rotate the token as it expires. I want to caution against this and suggest it could open you up to a timed attack. If you wait till the token is expired, and thus otherwise invalid, before handing out a replacement, that old token will not be blacklisted. That means for the duration of the leeway the token may be used to generate a hostile client new tokens of their own.

The simple solution is to rotate your tokens before they expire. Which will then blacklist the old token, making sure it can be used only once to generate a new token.

While working with JWTs David pulled out some of the code from his projects, and I polished it into a gem called hive-xyz/keeper. It uses ActiveRecord style syntax and feels right at home in rails. Check it out at: https://github.com/hive-xyz/keeper

Note: Currently it is not published to ruby-gems. I didn’t want to pollute needlessly and allocate gem names. If enough people are interested in using our extension, I will happily upload it.

--

--

Zane Wolfgang Pickett

Domesticated Sushi Lover. All my regular expressions are my own.