Image for post
Image for post
Image Source: @dakota.lillie

How do I use JWT Authentication in production?

I’ve heard people saying that JWT(JSON Web Token) is insecure, try to avoid it and many other things, and they’re not completely wrong. They have fair points against JWT. So, today in this article I’ll show some best practices which I use to make this process much secure.

If you don’t know what JWT is, how it is structured or how it encodes/decodes data, please read this introduction first.

Edit1: I’ve tried to implement all the features in this GitHub repository. Do check it out.

What are the drawbacks?

It is important to make the list of drawbacks first so that we can understand why there are many people not using JWT tokens for authentication.

  • Anyone can read the payload of a JWT token. If you don’t know this and want to verify, paste your JWT token here and see the output.
  • By default, JWT uses HS256algorithm, which works on the private key encryption. If you’re not the only developer (which is obvious in the production) and have no control over who uses the private key, it can easily be leaked and anyone can generate the token and get the access.
  • I’ve also read some blogs that it is possible to brute force HS256.
  • If you use RS256 algorithm, which uses public key encryption, you don’t have to worry about any key. But, there are very well knows attacks on these algorithms (e.g. attacks on RSA with PKCS #1v1.5 Padding, RSA with OAEP Padding, Elliptic Curve Diffie-Hellman etc).
  • If you generate any token without including exp in the payload, that token becomes valid forever.
  • Some people append tokens in the URL and even after logging out of the browsers, that URL gets cached and sometimes, other users who use the same browser can access the cached page.
  • Sometimes, there is only a single JWT Authentication server for multiple apps and if it is not properly configured, people can access other apps seamlessly.
  • While developing the system, developers store the JWT token somewhere else and also add a second layer to authenticate it. This approach seems quite good but it exposes all the token to the developers and they can misuse the token.

Please educate me if you know some other potential drawbacks of JWT Authentication.

Image for post
Image for post

You might be wondering that why one should use JWT for authentication if it has so many drawbacks. But if you’ve read the introduction link given at the beginning, you’ll agree that it is one of the simplest ways of authentication, and we can easily overcome these security threats(because if we can’t, there is no point of writing this blog).

Solution and some best practices which I use!

Always preferHTTPS over HTTP to transmit JWT tokens, so that no one can get the original token in between. It reduces the chances that someone extracts the JWT in between and read the payload or reuse the token.

But it is still possible that if someone has the physical access to the client’s PC or the client runs any malicious script, the attacker can see the token. So never include any sensitive data inside the payload of any token. If possible, try to generate the primary key using UUID and only append it with the payload.

As I said, if you don’t add exp (expiration time), a token becomes valid forever. So always add exp in your token. Also, try to make JWT token’s expiration time as small as possible. Because if some unauthorized person gets the token, he/she can’t misuse it for long. But, only adding it doesn’t make JWT any secure. You must include iat (issued at), inside the token. It makes the token somewhat unique. But if you want to be sure that the token is unique and also monitor which token is used to do which type of task, add uniquejti (JWT Token ID).

To prevent the users of some app to access your other apps, include iss (issuer of the token) in the payload. If you want some users to access only some paths of your app, either add those paths in your token or validate them explicitly in the backend using a uniquejti.

First, try to avoid this. Don’t append your tokens in a URL. It makes the token visible to everyone. But still, if you don’t have any choice and want to add the token in a URL, make sure you don’t let browsers cache your page by adding some meta tags, middlewares or whatever it takes. Because that’s not your users’ fault. They had properly logged out, it is you who didn’t properly architect/code your URLs or the whole app. It makes you and your app less credible.

I guess this is the biggest issue for a developer or a team as you don’t know who leaked the key or sometimes you don’t know whether your key is leaked until it’s too late. For that, I suggest using some other layer for validating the token.

If your app is not handling much traffic, it doesn’t really matter whether you choose Redis, MongoDB or any other way to store your data. But if there is heavy traffic or you want to scale your product later, you can useRedis. Also Google for the Redis’ benchmarking.

Ideally, you generate and send a JWT token in the response, after a successful login. At that time, before sending the response(before — because if it throws an error, your token becomes invalid in this approach), store this token in Redis.

Now if a user makes a new request with a token, first, search for that token in Redis. If you can’t find it there, send the response saying that the user is unauthorized. But if the token is there in your Redis, validate it using your backend because it is possible that it has been expired but not yet been removed from Redis. If your backend says that the token has been expired, send the response with the error and also remove that token from Redis.

There are some cases where you store your tokens in Redis and a user never returns, he/she clears his browser’s storage, start using a different browser or something which makes this token persist forever inside Redis. So don’t forget to set a cronjob (multiple times a day if possible) to remove all the expired JWT tokens.

A simple solution to this problem is, just make the hash of your JWT token and then store it in Redis. Same goes for the validation — first hash, then search.

Image for post
Image for post

Some other precautions

  1. Registered Claims
    sub (subject), aud (audience) and nbf (not before) are some other registered claims.
  2. Public Claims
    Which you add on your own. (e.g. user id)
  3. Private Claims
    Custom claims between parties that agree on using them to share the information.

Explanation of all the claims are given in this link in the payload section and details of each element of these claims are described here. As a developer, you must know what are these claims and prevent the collision between these claims.

Conclusion

I personally believe that using JWT authentication alone is not a good idea in a production environment. For the beginners, the setup which I showed might sound a little bit extreme but it makes your product much secure.

It doesn’t matter what you use for the authentication. If you don’t implement the whole system properly, you can never make a secure system.

Footnotes

If you are thinking that still there is a chance that we end up compromising the whole authentication system, please let me know. We can discuss and probably we can help to make the internet more secure.

Written by

Subscribe to gosink.in to get latest post updates on tech and design. AI | Web development | Blockchain

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store