When should I use JWT? What problem does JWT solves? For beginners

This is my story discovering the JSON Web Token benefits: 12 months ago I started working in a personal project: An App to see the best Photo Spots in the world (iOS, Android). During those 12 months, I attended to 12 JavaScript MeetUp. 12 meetings where I always had the same conversation with different people:

- (Me) Guys, I have to keep a user logged in an REST API, in a mobile App.
- (Devs) You have to use JWT
- Oh! Nice. Thanks. Now, tell me, how JWT solves my problem?
- I’m not sure, but people use it.
- Do you use it?
- Yes, but that was backend devs work.
- So, how can you be sure that JWT solves my problem?
- Because we use it.
- …

After last meeting I decided to do my own research. I was not happy at all with the research because I realized that in the past 12 months I could not find a really good article when someone says WHAT and HOW JWT solves problems. Most of JWT articles explains how JWT works, but they don’t answer the question: “How does it solves the problem?”

Here, again, the regular conversation:

- JWT solves your problem because JWT ensures that some data in the frontend was not modified
- How does “ensuring some data was not modified in the frontend” solves my problem?
- I don’t know, but now you are sure that your data was not modified
- What data?
- Whatever data you want
- But, what data should I get secured with JWT?
- … Whatever data you want

And this, my fiend, is the way that you should NOT answer questions.

So, in this article I’ll try to explain you:

  1. The Necessity
  2. The Problem
  3. The Solution (JWT).

Because, it’s actually true: JWT solves the problem, but HOW?

:pray: I believe you have some knowledge about REST API and MD5/hashes. If not, please go to read about it before continuing.

The Necessity

We have an App. A mobile App or a Web App. It doesn’t matter.

Scenario:

  1. The user, while logging, is gonna send the username and password.
  2. We are gonna check those credentials in the backend and if everything is OK we are going to send a response with SOMETHING (here start the problem) to identify the user in the next API calls
  3. Some minutes after, the user wants to change some data, let’s say, the first name. The user is gonna send us the new first name, and… what? Well… the user also needs to to send us that SOMETHING (sometimes called TOKEN) that we sent them in the login. Why? Because we need to identify who is trying to change their own first name.

There we have the necessity.

  • We need to find what is that SOMETHING to identify the user. Some kind of credential.
  • That SOMETHING should identify only 1 user, and there should not be a way to change it (to avoid identity impersonation).

So, our first though could be: “I need to send SOMETHING to identify the user. What if I send the User ID?”

Let’s say that your users in your database are identified by incremental numbers. For example: 1, 2, 3, etc.

In the past, we never sent the user ID as that “SOMETHING”, because we know that users actually can change it for another value (it’s pretty easy in web apps and mobile apps), so, if the user change that ID, the user is gonna be representing another user. We are gonna change the first name of another user.

For example:

  1. The user “John” logs in.
  2. We send the User ID (120) to identify the user
  3. The user change the identification from 120 to 121 (the Jack’s user ID)
  4. The user change its own first name sending us the new first name and the new faked User ID: 121
  5. The backend receive that information and change the first name of user 121.

BUM. Problem. John just replaced Jack. We have to avoid it.

The sum up, our necessity is: We need to send SOMETHING to the frontend, to identify the user IN A SECURE WAY.

The Problem

You already know the problem. The user can change the ID that we send to identify them. If the users are able to change the ID for another valid ID, they are gonna be to impersonate someone else identity. It’s a huge vulnerability.

The Solution

How did we solve it with JWT?

The JWT token approach is very simple: You send the “120” number to the user, but you also are gonna send him some data that you are gonna use to validate that the “120” was not changed.

JWT basically contains a function that you call it sending 2 things:

  1. The data you want to send to the user
  2. The secret phrase

And that function is gonna return a big token that it’s what you have to send to the user while log in.

Important: That token IS NOT ENCRYPTING the data.

That big token contains all the data you want to send to the user, and also a signature that works as a “data was not changed” validator.

This is the scenario:

  1. John send the username and password to login
  2. Username and passwords are OK.
  3. Backend is gonna create the JWT (Token) using this object to identify the user: { “id": 120 }, and also the secret phrase: “HELLOWORLD!”
  4. JWT returns this token: “eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MTIwfQ.B5TusFY3hGZ5EFFDA60vuGRsFkm29usx8J4HefWhzuc”
  5. We send that token to the user.

Then, John can just realize that it is a JWT, so he can just paste that token in https://jwt.io/ and he is gonna see that the data that we sent is { “id": 120 }, and even he is gonna be able to change `120` for `121`. A new token is gonna be created, but when John send us that token again, trying to change his first name, we are gonna check if that token is valid with the secret phrase “HELLOWORLD!”, and JTW is gonna let us know that it is actually invalid, due to John created a new token, with new data, but John didn’t know our secret phrase. So, in that moment, we can just stop the process and avoid changing the first name.

So, to sum up:

  • JWT contains a function that given a JSON and a secret phrase, returns a Token that contains the JSON and a Signature (both in kind of base64 format).
  • You have to send that token to the user and the user should send you that token again in every single new API call after login.
  • JWT has another second function that is used to validate tokens. We just have to call that function sending the token that the user send us and also the secret phrase. This function is gonna return some value to let us knows if the user changed or not the token that we sent him. If user changed it, we’ll know that it’s a malicious user.

Important: While validating the Token, JTW not only let you know if the token is valid or not, but also returns the Data Object that was used to create that token.

So, now, it’s not necessary anymore to send SECRET data to the frontend, in order to identify a user. We can just send an ID in a JWT format, and we’ll know that nobody changed it.

ProTips:

  1. Remember that you should not send sensitive data there, due to JWT doesn’t encrypt your data. JWT only ensures that nobody changed the data. People can see what data you are sending in that token.
  2. Due to JWT now only tell you if the Token is valid or not, but also return the Data Object that was used to create the token, you can use that Data Object to get more context about who is the user. For example, when you create the token, in the login, you can use this Data Object: { “id": 120 , isAdmin: false, age: 28 }, so then when the user send us the token again, you’ll know if the user isAdmin or not, the age, or whatever you want.