How I Fixed JWT Security Flaws in 3 Steps
Tags: javascript, jwt, security, frontend
Published: 2019-10-14 08:31:57

---
title: How I Fixed JWT Security Flaws in 3 Steps
published: true
description: Common JWT security mistakes and simple ways to fix them.
tags: javascript, jwt, security, frontend
cover_image: https://thepracticaldev.s3.amazonaws.com/i/yekmwrkd11shvfqquvy6.jpg
---

### There are just too many ways to do JWT wrong. :cry:

And I fell for some... Don't panic, but it's likely to be your case as well.

Check these 3 commonly overlooked security areas on JWT implementations. It will take only a few minutes.

---

# 1) Broken libraries

There are +1,600 libraries [matching "jwt" on npm](https://www.npmjs.com/search?q=jwt). :flushed:

![npm jwt libraries](https://thepracticaldev.s3.amazonaws.com/i/6rj1v12f7myg36pt6fu9.PNG)

And [+300 on Pypi](https://pypi.org/search/?q=jwt). :astonished:

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/2nijzxuld30pejlvu5st.png)

Do we need them all? Certainly not. Are they all secure? I won't trust. :confounded:

There are [several ways](https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/) your JWT library of choice might be compromised.

### Can we cut to a simple solution?

Yes, I am also bored with security blah, blah, blah. :zzz:

Go to [this resource](https://jwt.io/#libraries) and double-check which libraries follow practices proven to be safe. Most will by now. But better safe than sorry.

---

# 2) Unsafe token generation and distribution

The _joyfull_ implementation: :four_leaf_clover:

> a. Frontend requests user authentication
> 
> b. Backend authenticates and generates JWT
> 
> c. JWT is sent in the response body payload
> 
> d. Frontend store JWT in the `localStorage`

Ah, yes... The world would be beautiful without [bad guys](https://hackernoon.com/can-timing-attack-be-a-practical-security-threat-on-jwt-signature-ba3c8340dea9) and if [ugly things](https://medium.com/101-writeups/hacking-json-web-token-jwt-233fe6c862e6) could [not happen](https://www.nccgroup.trust/uk/about-us/newsroom-and-events/blogs/2019/january/jwt-attack-walk-through/). :innocent:

![Cupcakes](https://thepracticaldev.s3.amazonaws.com/i/ulqxllccxbtqk6ah6wdf.jpg)

Well. Back to the real world. :sunglasses:

Avoid following the above outline.

To help with items (a) & (b), make sure you selected a JWT library that follows best practices. Or that you implemented correctly on your own. Not that difficult really. Just care enough.

It's also [good practice](https://cheatsheetseries.owasp.org/cheatsheets/Logging_Cheat_Sheet.html#which-events-to-log) to log every authentication attempt (success and failures) and all contextual data you may possibly have.

JWT is frequently used in [Serverless](https://serverless-stack.com/chapters/what-is-serverless.html) environments (because both are stateless, niiice!).

If that's your case, make sure you have [professionals monitoring your logs](https://dashbird.io/blog/top-serverless-monitoring-tools/?utm_source=dev.to&utm_medium=referral&utm_campaign=article&utm_content=educational) and alerting you proactively. If that's not your case, the advice still holds. :wink:

To address items (c) & (d):

> **Do not** send JWT in the **response body** payload
> 
> **Do not** store JWT in **`localStorage`**

Problem is: any JavaScript code in your frontend is able to access the JWT. And do whatever it wants.

## And that's [dangerous](https://developer.okta.com/blog/2018/06/20/what-happens-if-your-jwt-is-stolen).

![scorpion](https://thepracticaldev.s3.amazonaws.com/i/6urds06z62day9urqo5i.jpg)

Imagine what can happen if someone manages to inject malicious code in your frontend... and get all your users' JWTs?... Hum... Houston...

No. Instead, the backend should set the JWT as a cookie in the user browser. Make sure you flag it as [`Secure` and `httpOnly` cookie](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#Secure_and_HttpOnly_cookies). And [`SameSite` cookie](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#SameSite_cookies). Boy, that's a multi-flavor cookie.

This way, the JWT will be available to the backend in all subsequent requests, while remaining outside the reach of potentially dirty JS hands.

In your response body payload, send only what's necessary for the frontend to provide the features expected by the user. Did I mention to not include anything sensitive here? Should not.

I know. A cookie is not as cool as `localStorage`. But, look, they can be colorful! And **SAFE**. He's our friend. Let's treat him well. Deal? :raised_hands: :cookie:

![Cookies/Macarrons](https://thepracticaldev.s3.amazonaws.com/i/shhl4a23fvu12hmc4l6c.jpg)

---

# 3) Not handling secret keys securely

Any JWT implementation will involve some sort of secret data. Regardless of using a symmetric (one secret key) or an asymmetric (public/private keys) way to sign tokens.

> Personally, I prefer symmetric implementations with HMAC. Simplifies things. But sometimes I use asymmetric RSA. Lately, I have been using the latter only. Well, they'll never know which one I really use. :stuck_out_tongue_winking_eye:

No one should ever know how **YOU** implement JWT either. Not to mention your secret or private keys.

Things you should avoid doing with your secret/private key when possible:

* :computer: Storing in a `config` file and committing to your Git repo
* :mega: Sharing with your team on your Drive, Dropbox, Slack, whatever
* :recycle: Having the same keys for local, test, and production environments

Instead:

* :v: Distribute keys for your development team to use only in local and testing environments
* :thumbsup: Store production keys in a safe place, only available to the production app
* :closed_lock_with_key: Keep the production keys away from prying eyes, load them as environment variables, on-demand, protected against unintended access

---

Further reading:

* [Auth0 blog post](https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/) about vulnerabilities on JWT libraries
* OWASP cheatsheet [about JWT](https://cheatsheetseries.owasp.org/cheatsheets/JSON_Web_Token_Cheat_Sheet_for_Java.html)
* OWASP cheatsheet on [managing security keys](https://cheatsheetseries.owasp.org/cheatsheets/Key_Management_Cheat_Sheet.html)
* [Critical security logs](https://dashbird.io/blog/securing-serverless-with-critical-logs/?utm_source=dev.to&utm_medium=referral&utm_campaign=article&utm_content=educational) on Serverless applications

---

**Full disclosure**: I work as a Developer Advocate at [Dashbird](https://dashbird.io/?utm_source=dev.to&utm_medium=referral&utm_campaign=article&utm_content=educational).

---

Image credits:

* Cover image: [Vincent van Zalinge](https://unsplash.com/@vincentvanzalinge?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/tiger?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)
* Cupcakes: [Viktor Forgacs](https://unsplash.com/@sonance?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/candies?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)
* Scorpion: [Shayna Take](https://unsplash.com/@shayyyyyyyna?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/scorpion?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)
* Cookies (not really, they're actually _macarrons_): [Mockaroon](https://unsplash.com/@mockaroon?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/cookie-colorful?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)