In this article we are going to analyse the advantages and disadvantages of using an authentication system based on JWT (JSON Web Tokens) compared to the traditional scheme based on the use of cookies and sessions.

To make it easier to understand, I'm going to present you with a series of summaries, which I've adapted from interesting resources I found on the Internet. If you want to check the original sources, you can find the links at the end of the article.

Without further ado, let's get started.

 

 

Introduction

To better understand this article, you need to know beforehand What are cookies and their relationship with server-side sessions?.

If you are clear about the difference between cookies and sessions, and how they operate together, then we can continue to the first question.

Cookies or Tokens? Which is better?

Question

I've been using cookies and sessions to manage user authentication in my web applications, and I'm happy with how simple they are to use.

However, an iOS developer told me that the new and most appropriate thing to do is to use JWT (JSON Web Tokens)).

He told me that JWT is the way to go for implementing authentication in native mobile apps. Without giving examples, he simply commented that Android and iOS apps have problems with cookies.

I have searched for information, but I have not found anything that proves that JSON Web Tokens are superior to Cookies. What's more, they are so similar to me that I have not been able to find an important difference, nor why their use with native mobile applications is recommended.

At least in my opinion, it is possible to use Cookies in iOS development.

So my question is, for a mobile application, what advantages does an API that makes use of JWT instead of Cookies for user authentication?

 

Reply

We, as software developers, have a tendency to apply everything new we find. To give an example: if we suddenly find ourselves with a hammer that we have not seen before (despite being only one variant of the many we know), we begin to see everything as a "nail". We feel the need to apply everything new that we are learning (in the vast majority of cases).

Now, returning to the original question:

  • It is important to mention that neither JWTs nor Cookies constitute in themselves an authentication mechanism.

  • The former only defines a token format, and the latter is a state-management mechanism for HTTP requests.

  • Only with this do we determine that it is incorrect to say that one is superior to another.

It is correct however that both are widely used in authentication systems.

Traditionally, web applications have used cookies (in conjunction with sessions) to keep track of users who have logged in. This way, they don't need to send their credentials on every request.

Generally, the content of a cookie is determined by a unique (randomly generated) identifier. This ID allows the server to find the corresponding session data for each user.

However, in API development it is more common to accept tokens (mainly in JWT format) so that the server decides whether or not to grant access to the person making the request.

This is because:

  • Traditionally, the Main type of customer (to visit web applications) has been the web browser (web browser), which features a Full support for cookies.
  • But APIs today are also used by much simpler HTTP clients, that do not support cookies natively.

Cookie-based authentication is convenient for browsers, but beyond them, a token-based approach makes more sense for other types of clients (since tokens can be transported through parameters, headers, or as part of the body of HTTP requests).

That is, if an API supports tokens then it will increase the range of clients it can serve, so it is more convenient if the API must be used beyond web browsers.

Today The use of cookies in native mobile applications is possible, but in summary: JWTs have an advantage over cookies only because their use is more common. By following this approach, we can have more learning resources, SDKs, information on the most well-known vulnerabilities, and so on.

 

Token-based authentication VS cookie- and session-based authentication

Below we are going to review how cookies (in conjunction with sessions) and tokens work, so that it is easier for us to highlight the differences later.

Diagrams, of a traditional authentication system, and of a token-based system

Cookie-based authentication

Cookie-based authentication has been the default (and proven) method for handling user authentication for a long time.

Cookie-based authentication presents a state (en stateful).

When logging in, after a user submits their credentials (and these are validated), the server logs data (in order to remember that the user has successfully identified themselves). This data that is recorded in the backend, in correspondence with the session ID, it is what is known as Status.

On the client side, a cookie is created to store the session ID, while the data is stored on the server (and is called session variables).).

The flow followed by this traditional authentication system is as follows:

  • A user enters their credentials (data that allows them to log in)
  • The server verifies that the credentials are correct, and creates a session (this can correspond to the creation of a file, a new record in a database, or some other server-side solution)
  • A cookie with the session ID is placed in the user's web browser
  • In the following petitions, the session ID is compared to the sessions created by the server
  • Once the user is disconnected, the session is destroyed on both sides (both on the client and on the server)

Token-based authentication

Token-based authentication has gained prevalence in recent years due to the rise of Single Page Applications, web APIs and the Internet of Things (Internet of Things in English).

When we talk about token authentication, we usually talk about authentication with JSON Web Tokens (JWT).

While there are different implementations, JWTs have become the de facto standard. With that in mind, in the rest of the article, tokens and JWT will be used interchangeably.

Token-based authentication is stateless (en stateless).

The server no longer stores information about which users are connected or which tokens have been issued. This is because each request made to the server is accompanied by a token, and the server verifies the authenticity of the request based solely on the token.

As we mentioned before, JWT defines a format for tokens. But JWT does not tie us to any data persistence mechanism on the client side and nor to any rules of how the token should be transported.

Tokens are usually sent as a Authorization header, with the courage Bearer {JWT}; but they can also be sent in the body of a POST request or even as a query parameter.

Let's see how it works:

  • A user enters their credentials (data that allows them to log in)
  • The server verifies that the credentials are correct, and returns a signed token
  • The token is stored on the client side, commonly on the local storage (but it can also be stored in the session storage or even as a cookie)
  • Subsequent requests to the server include this token (via a Authorization header or any of the other methods mentioned above)
  • The server decodes the JWT and if the token is valid it processes the request
  • Once the user disconnects, the token is destroyed on the client side (no interaction with the server is necessary)

Benefits of token-based authentication

After understanding How they work In both approaches, let's look at the advantages that token-based authentication presents over the traditional cookie-based approach.

Stateless, scalable, and decoupled

Probably the biggest advantage of using tokens and not cookies is the fact that they offer stateless authentication).

From the backend you don't need to have a record of the tokens. Each token is autonomous: it contains in itself all the data necessary to confirm its validity (as well as specific information of the user who has logged in).

In this way, the server's only job is: Sign tokens upon successful login, and Verify that incoming tokens are valid.

Cross Domain and CORS

Cookies work well with a specific domain (or subdomain), but when it comes to managing cookies across different domains, handling becomes complicated.

In contrast, a token-based approach with CORS enabled makes it trivial to expose APIs to different services and domains.

Because a token is required and verified on each of the backend calls, as long as there is a valid token, requests can be processed. On this, there are some details that we need to take into account, and we will address them in the Common Questions section).

Save data to JWTs

With a cookie-based approach, we simply save the session ID.

Tokens, on the other hand, allow us to save any type of metadata, as long as it is a valid JSON.

The JWT specification states that we can include different types of data (called claims), and that can be saved as reserved, public and private data.

Depending on the context, we can choose to use a minimum number of claims, and save only the user ID and the expiration of the token, or we can include additional claims, such as the user's email, who issued the token, the scope and/or permissions available to the user, etc.

Performance

When using cookie-based authentication, a session lookup (corresponding to the identifier sent by the client; either in files, in a traditional SQL database, or a NoSQL alternative) must be performed from the backend. In that case, it is very likely that the back and forth will take longer compared to the decoding of a token. In addition, because additional data can be stored in tokens (such as permission level), we can decrease the number of lookups required to obtain and process the requested data.

For example, suppose we have a resource /api/orders in our API that returns the last orders registered in our application, but only users with an administrator role have access to view this data.

In a cookie-based approach, once the request is made, from the backend it is necessary to make a query to verify that the session is valid, another search to access the user's data and verify that they have the administrator role, and finally a third query to obtain the data.

On the other hand, using JWT, we can save the user's role in the token. Thus, once the request is made and the token is validated, we need to perform a single query to the database (to access the information of the orders).

Mobile-ready

  • Modern APIs don't just interact with the browser.

  • Writing an API correctly means that it can be used by both browsers and native mobile platforms (such as iOS and Android).

  • Native mobile platforms and cookies do not work very well together, as a whole series of considerations must be taken into account for their proper functioning.

  • Tokens, on the other hand, are much easier to implement (on both iOS and Android). They are also easier to implement for Internet of Things applications and services (which do not incorporate the concept of cookie management).

Common Questions and Concerns

In this section, we'll look at some common questions and concerns that frequently arise when discussing the topic of token-based authentication.

The main topic is security, but we'll also look at how big tokens, storage, and encryption can be.

JWT Size

The biggest disadvantage of token-based authentication is the size of the JWTs.

A session cookie is relatively small compared to (even) the smallest token.

Depending on the case, the size of a token can be problematic if we load it with many claims.

Remember that each request to the server must include the corresponding JWT.

Where to store tokens?

With token-based authentication, we have the option to choose where to store JWTs.

Commonly, JWTs are stored in the local storage of browsers, and this works well for most cases.

There are some drawbacks to take into account if we store JWTs in the local storage (We mention them later).

We can store a token in a cookie, but the maximum size of a cookie is 4kb, so it can be problematic if the token has multiple claims. We can also store a token in the session storage, which is similar to the local storage, but it is deleted the instant the user closes the browser.

XSS and XSRF protection

Protecting our users and servers is always a priority.

The most common concerns developers have when deciding whether or not to use token-based authentication are about security.

Two of the most common attack vectors that websites face are:

  • Cross Site Scripting (XSS), and
  • Cross Site Request Forgery (XSRF or CSRF).

Cross Site Scripting attacks occur when an external entity can execute code on top of a website or application.

The most common attack vector here is if a website presents inputs that are not properly validated.

If an attacker can execute Javascript code on your domain, your JSON Web Tokens are vulnerable.

Many frameworks automatically validate (sanitise) data inputs and prevent arbitrary code execution.

If you're not using a framework (that performs this validation), you can also use plugins (such as Caja Compiler, a tool developed by Google to help with this task).

It is recommended to use a framework or plugin to have this problem solved, versus the alternative of creating your own solution.

Cross Site Request Forgery attacks are not a problem if you are using JWT with the local storage. On the other hand, if you store the JWT in a cookie, you will need to protect yourself against XSRF.

If this concept is not familiar to you, you can check out this video explaining in greater detail how XSRF attacks work.

Fortunately, preventing XSRF attacks isn't very complicated. In short: to protect against XSRF attacks, our server, when establishing a session with a client, must generate a unique token (it is important to be clear that it is not a JWT). Then, whenever data is sent to the server, a hidden input field (hidden input field) will contain this token and the server will validate it to make sure the tokens match.

Another good way to protect our users and servers is to have a short expiration time for tokens. This way, even if a token is compromised, it will quickly become worthless. In addition, we can maintain a blacklist (blacklist) of compromised tokens and thus prevent these tokens from being used. Finally, a definitive approach would be to change the signing algorithm, which would invalidate all active tokens and require all users to log in again. This approach is not recommended, but is available in the event of a serious violation.

Tokens are signed, but not encrypted

A JSON Web Token is made up of 3 parts: header, payload, and signature.

The format of JWTs consists of joining these parts using a dot between them: header.payload.signature.

For example, if we were to sign a JWT with the HMACSHA256 algorithm, the secret key 'shhhh' and the following content (payload):

{
  "sub": "1234567890",
  "name": "Ado Kukic",
  "admin": true
}

The JWT generated would be:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFkbyBLdWtpYyIsImFkbWluIjp0cnVlLCJpYXQiOjE0NjQyOTc4ODV9.Y47kJvnHzU9qeJIN48_bVna6O0EDFiMiQ9LpNVDFymM

The most important thing to note here is that this token is signed using the HMACSHA256 algorithm, but the header and payload are encoded in Base64URL (they are not encrypted).).

If we go to jwt.io, paste the token and select the HMACSHA256 algorithm (abbreviated as HS256), we can decode the token and read its contents. Therefore, it goes without saying that sensitive data, such as passwords, should never be stored in the payload.

If you need to store sensitive data in the payload, you can use JSON Web Encryption (JWE). JWE allows the contents of a JWT to be encrypted so that it is not readable by anyone but the server. Although it is possible to encrypt the content of a token, it is not really necessary for an authentication system (what is important is that we use the HTTPS protocol so that the messages we exchange with the server travel encrypted).

Authentication: Using JWT vs Sessions

JWTs provide a Mechanism for maintaining the state of a session on the client side, instead of doing it on the server.

Therefore, a more appropriate question would be, "What are the benefits of using JWT over using server-side sessions?" (server-side sessions).

With server-side sessions, it is necessary to save active sessions in a database or in memory; and on the other hand, to ensure that each client is always served by the same server. Both have drawbacks.

  • If a database (or other centralised storage) is used, this can become a bottleneck (another concern), since a query is required to be made when each request is attended to).

  • With an in-memory solution we limit our horizontal scaling, and sessions are affected by network issues (such as server reboots)).

Moving the session to the client side means that we no longer need to maintain a server-side session, but we run into new challenges:

  • Store tokens securely
  • Transport them safely
  • JWTs (representing sessions) can be difficult to invalidate
  • Ensure reliability over the data sent by the customer

These problems are shared by all client-side session mechanisms (such as JWTs)).

JWT in particular already solves the last of the points mentioned.

¿But what is a JSON Web Token?:

It is a string, a set of characters, that contains a bit of information. For user sessions you can include the username and expiration time (date and time). But it can actually represent anything, even a session ID or the full profile of the logged-in user. Although, please, this should be avoided.

It has a secure signature that prevents malicious external actors from generating fake tokens. You need to access the server's private key to sign them; and thanks to this signature it can be verified that they have not been modified (since the server signed them).

They are sent on every request (just like cookies). They are commonly sent through the Authorization header of HTTP requests, but curiously you can also use cookies to transport them.

Each token is signed, and thus the server can verify its validity. The server relies on your ability to sign the tokens securely. For this there are standard libraries, which are recommended on the implementations that one can make oneself.

In order to securely transport the token, it is appropriate to send it over an encrypted channel (usually httpS).

With regard to the secure storage of the token on the client, we must ensure that criminals cannot access them. This (mainly) means preventing JS from other people's sites from loading onto our page, because it is possible to read the token and therefore capture it. This is mitigated using the same strategies used to mitigate XSS attacks.

If you have the urge to invalidate JWTs, there are definitely ways to achieve it.

Storing data in a temporary table only for users who have requested that "their other sessions be closed" is a very good alternative.

If an application needs to invalidate sessions specifically, in the same way you can save the ID of each session and have a table of "deactivated tokens". This table only needs to retain records based on the maximum allowable duration for tokens.

As you may have noticed, The ability to invalidate tokens It partially negates the benefit of client-side sessions, in the sense that a state must be maintained on the server (of deactivated sessions). However, this table has to be much smaller than the original session table (server-side sessions), so searches are still more efficient.

Another advantage of using JWT is that it is easy to implement using the libraries available in (probably) every language that may exist. It is also completely divorced from its authentication scheme: if you switch to using a fingerprint-based system, you do not need to make any changes to the session management scheme.

In short, JWT solves some of the shortcomings of other session techniques:

  1. "cheaper" authentication, because you can delete a database query (or at least have a much smaller table to query!), which in turn enables the Horizontal scalability.
  2. "Tamper-proof" client-side data".

While JWTs do not respond to other issues, such as secure storage or transportation, they do not actually pose any new safety issues.

There is a lot of negative review of JWTs, but if they are implemented with the same care as other types of authentication, in the end it is the same.

One final note: it is not correct to compare Cookies vs Tokens. Cookies are a mechanism for storing and transporting data, and therefore can also be used to store and transport JSON Web Tokens.