Bits and Pieces

Insightful articles, step-by-step tutorials, and the latest news on full-stack composable software development

Follow publication

Why Using Tokens and Cookies Together is Better for Web App Security

--

Over the past decade, web authentication has come a long way. I can still remember how we developed the login pages and password storage with hashes and salts for extra security. We used Cookies in the browser with Sessions to recognize the users after the first login.

Nowadays, we talk about JSON Web Tokens (JWT). There are bespoke Secure Token Services (STS) that issue these tokens after verifying user credentials. We even send Tokens along with HTTP requests to the backends. The concept is simple, where we keep the backend stateless as RESTful services, that validate the Token before sending any data back to the browser.

But does this mean that we don’t need Cookies and Sessions anymore? If you carefully observe popular web applications like Gmail, Facebook, Office365, and Amazon, they still use Cookies. So are these applications old fashioned, or are we missing something here?

Tip: Use Bit (Github) to share, document, and manage reusable components from different projects. It’s a great way to increase code reuse, speed up development, and build apps that scale.

Bit supports Vanilla JS, TypeScript, React, Angular, Vue, and many more.

Misconception about Cookies

I have met many developers who considered Cookies as a legacy technology. The common misconception happens when we use single-page applications for the frontend and a RESTful API for the backend.

RESTful APIs and Cookies, they don’t go along, right? This understanding seems to be valid unless we go deep down, asking the question, is our web application backend is truly an API or not. Unless you share your backend with mobile apps or any third-party integrations, it’s unlikely to end up becoming an API.

If you have already used your backend as an API, I hope you truly understand the cost behind the decision where you sacrifice the agility of web application development for API governance. The teams I worked with do the frontend and backend changes together, and ship features fast rather than spending their precious time on backend API governance.

If you are interested in knowing more, you can read my article on Your Web App Backend is NOT an API. Let’s Face it!. For web and mobile apps, I recommend the use of BFF pattern which seperates the web application concerns from mobile apps & etc.

So if you keep your web backend dedicated to the web application, the doubt about Cookies simply disappears.

But isn’t the Tokens a better replacement for Cookies?

JSON Web Token(JWT) is an open standard to transmit information across multiple parties securely. No doubt, these Tokens have their strengths. Since OpenID Connect and OAuth2 use Tokens, almost all secure token services (STS) uses the JWT format out of the box. Since these tokens are digitally signed, it becomes easy to verify them in the backends with the support of libraries that implements the standards. You can find Token validation libraries for almost all the programming languages out there.

Considering these facts, it makes a perfect candidate for an end to end web application authentication.

However, I see two main challenges when we use Tokens for the complete lifecycle of the authentication.

  1. The inability to revoke the Token (applies to id_tokens and access tokens): Once you logout, the application can only delete the Token from the browser cache. However, if someone gets on hold with the Token, he/she can log in to the application during the token validity period. This point could be a severe risk for many business applications.
  2. Difficulty in refreshing the Token: You can argue that there are options such as silent-refresh for implicit flow and refresh token in code grant flow to get new tokens before the existing Token expires. However, if you look into the details of complexity it adds to your code with security challenges, I doubt whether it’s a rational decision when we have the other option of using Cookies and Sessions.

Cookies are better at handling user Sessions.

If you simply compare the code and concerns involved in refreshing the access tokens with sliding expiration of Cookies, it becomes apparent how easy it is to deal with Cookies.

It also solves the problem of immediate revoking of the Session when the user logs out. Besides, the sliding expiration is precise, and the approach is hardened for CSRF and XSS by deploying standard best practices for security. Similarly, we can attach any user details to the SessionSession in the backend for any subsequent requests.

Using Tokens and Cookies together

Using Tokens and Cookies Together for Authentication

The best approach I could recommend at the moment is to use both JWT and Cookies in combination. We can use Tokens for the first part of the authentication, as shown in the above diagram, marked with Red arrows.

The first half of the authentication flow

  1. The user first tries to access the web application that requires login.
  2. The backend issues a server redirect to the login page offered by the Secure Token Service (STS). Note: Here, there is a difference compared to using Frontend redirection when backend issues a 404 status code.
  3. The user enters the credentials, and for successful validation, STS issues a Token.
  4. STS issues a server redirect along with the Token in the URL, which is then transmitted to the backend.
  5. Backend validates the token, and claims are extracted from the Token. (Note: In cases like Code Grant Flow, there will be few additional steps, but still the concept is valid)

After that, the backend triggers the second half of the authentication flow, where we do the handover from Tokens to Cookie and Sessions.

The second half of the authentication flow

Using the claims (which also includes any user identity information), the Backend carries out the following steps.

  1. Establishes a Session to store user identity information.
  2. The Backend sends the server-side Cookie into the browser that’s linked with the Session.

Once we set the Cookie in the browser, it manages the sliding expiration of the Cookie. The browser also ensures that it is sent to the Backend for subsequent calls. The users can log out and remove the Cookie and destroys the Session immediately.

As you can see, with the addition of Cookies, we can efficiently address the two main challenges when we only use Tokens.

Besides, you can find most of the programming languages well equipped with libraries that are capable of establishing a Session upon receiving a Token. I have seen some of these libraries even doing the Token claims transfer to the HTTP Context with few lines of configuration code.

Summary

Typically, Tokens and Cookies are considered two different approaches for web application authentication. As I explain above, we can use these two approaches in combination to build more robust and secure web applications.

Furthermore, I would recommend using the Code Grantflow in combination with Cookies to establish the Session.

Besides, it’s essential to keep the token lifetime short as a best practice to reduce the risk if the Token falls into the wrong hands. Typically keeping its validity period shorter for about 5 mins or less is a better option. We can also use a server-side Cookie where the frontend doesn’t need to deal with any Cookie handling.

I hope the approach discuss here would become an eye-opener for most of you. If you have any questions regarding the areas I have discussed in this article, don’t hesitate to comment below.

Learn More

Sign up to discover human stories that deepen your understanding of the world.

--

--

Published in Bits and Pieces

Insightful articles, step-by-step tutorials, and the latest news on full-stack composable software development

Written by Ashan Fernando

Solutions Architect and a Content Specialist. For more details find me in Linkedin https://www.linkedin.com/in/ashanfer/

Responses (4)

Write a response