Stateful vs Stateless Authentication

بمس الله الرحمن الرحيم

Hello,

In software development, there are some terms that called “Stateful & Stateless".

These 2 terms are essential to determine the architecture of your application. Note that those term is very broad. And I will choose 1 good case that can perfectly represent stateful and stateless, which is Authentication.

Stateful Authentication

In Stateful Authentication, the server will remember / store the user’s piece of state, or data to determine whether this user is authenticated or not.

That information is called a Session. Session has an ID and contains the user’s info, such as username, or email.

Where do we store the session ?

Well, in a traditional stateful application, we store it in the server’s memory (RAM). In a modern application? let’s talk about it later ;).

Since the session data is stored in memory, the authentication service can check the auth status of a certain user pretty fast.

But of course it has a trade-off, storing data in memory increases the RAM usage. If there are so many users, the server can runs out of memory pretty fast.

How do we store data in the server’s memory ?

Well, the easiest way to do it is to use a global variable.


This is what happen when the client is logged in successfully

Stateful-Login flow

So, after checking the user’s credential, the server will generate a session ID, and then save a piece of the user’s credential along with the session ID in memory. Then returns the session ID to the client.

There are several ways to give the session ID to the user, the most convential way is to attach the session ID into the response’s cookies, and that cookie will gonna be saved automatically in the client’s application (browser or other app that do the authentication) without client knows about it.

And this is what happen when the client tries to access a protected resource

Statefull Protected Resources

If the session ID is attached in the cookie, the session ID is automatically included everytime user calls an API.

When Scalability Crashes the Party

When the app’s user increases, there’s a moment where one server is not enough anymore. Well we can do a vertical scaling, in which to increase the server’s hardware capacity, like RAM, etc. But it has a limitation on the max capacity can be increased.

Mostly, we do horizontal scaling instead. In which, we increase the amount of servers available.

But, doing so introduces a problem…

Stateful Problem

Usually, when there are multiple servers, we use another tool called Load Balancer to Balance the server’s load… duh.

Means that, there’s a 50-50 chance that our request will be routed to Server 1, or Server 2. (We use 50-50 for simplicity’s sake).

Let’s say we were routed to the Server 1 for the login action. It’s done smoothly, client gets the session ID.

Then, when you try to request the protected resource…

Stateful Problem 2

Guess what, the load balancer hates you, it routes your request to Server 2.

Server 2 has no idea about your session ID, hence it rejects your request and returns Unauthorized.

How to Mitigate that issue ?

There are couple ways to fix this.

The most obvious one is to not storing the session information in the server’s memory.

But then, where should we store it ?

Well, we can store it on the DB. Create a table there to store session information.

Stateful Store Session in DB

But, every time a request came in, we need to poke the DB. But it’s slow, especially if you use a RDBMS like MySQL, or PostgreSQL, or SQLServer.

Then how to make it faster ?

Well, I’d say this step is optional, and not necessary. Most of the time, storing the session in the RDMS is fine if the user can tolerate the additional response time for every authenticated request.

But, if we want to make it faster, then use another DB that utilizes in-memory storage. Such as Redis or Memcached.

That way, we can achieve the same performance as using the server’s memory. Keep in mind that, Redis & Memcached is really fast.

Stateful Use Redis

That way, even if there are 100 servers, the application could still recognize the user’s sessionID

Stateful scaling

Conclusion

By looking at the condition aboves, we can conclude that there are PROS & CONS of using Stateful Architecture.

PROS:

  • Server’s administrator can revoke the user’s session anytime. Just go to the session store, and delete it. So, administrator has a full control to its user’s session.
    • So, if there’s an occasion where the user’s sessionID gets stolen, that user can ask the server’s administrator to revoke the token.
  • Server’s administrator can see who are using the application
  • More secure, only the authentication service is able to extract the information from the session ID.
  • Session ID size can be small. cos all the sensitive information are stored in the database.
  • Usually session ID is returned to the user as a “HttpOnly” cookie. and HttpOnly cookie is not vulnerable to XSS attack.
    • And because cookies can only store at maximum 4MB, and the sessionID size is small. This is a perfect combination.

CONS:

  • Even though redis is fast, there’s an extra computing resource needed be spent to do the authentication. For example, the server always needs to connect to the external database to verify the session. I’d call this as an overhead.
  • Might need extra tools to do this properly. Extra tools = extra cost.
  • Less straightforward to implement. Because we need to handle the layer where we connect to the database to check the session.
  • Redis server can still be overwhelmed as the user increases, or as the data increases. So, when we scale up the system, we might need to scale up the redis server as well. And scaling up Redis instance has its own difficulties, so, it's an extra work here.

When should we use Stateful Design ?

  • When you want to have an ability to revoke user’s session anytime you want
  • When you want to have a feature to track user’s session.
  • When you want more security to the user’s sensitive information
  • When you are an awesome System Administrator / DevOps engineer that can scale up the system pretty well.

Stateless Authentication

Well, as the name suggests. Stateless is the complete opposite of stateful. The “session” is managed in the client’s side. As opposed to stateful, which is managed in the server’s side.

After successful login, the app will take the user’s information and encrypt it using a secret key to generate a token, then returns it to the user.

When user tries to access some protected resources, user need to send that token back to the server. Then the server tries to verify the token’s sign using the same secret key. And also verify the token’s expiry. If the verification succeeded, then the server considers this user as an authenticated user.

Stateless Login Stateless Request

So, as long as all the servers are using the same secret key, then it’s all good. They can still verify the token’s validity.

The most popular token generation tool out there is called JSON Web Token (JWT). If you want to implement a stateless authentication, i’d strongly suggest you to use it.

Extra things that you need to know about JWT

To play around with JWT, you can access jwt.io

This is the JWT's content

JSON Web Token Example

Red colored line is the header. It represents which encryption algorithm to use.

Purple colored line is the payload. It can contains any information that the server wants to put. So, the more the information, the longer it gets. The longer it gets, the bigger the JWT’s size will be.

Blue colored line is the** signature key**. It’s generated using the secret key I mentioned above.

Other than those, these are the things that you need to be aware of:

  • the purple line can be publicly accessed by anyone if they can get ahold of the token somehow.
    • To prove my point, try to copy this token. eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IlJhbmdnYSBSaWZxaSBQcmF0YW1hIiwiaWF0IjoxNTE2MjM5MDIyfQ.FzSqgN66Jv5iBuFsN5bBosjHT7oQZtD9jEP58p4CXSY
    • Then open jwt.io, paste it there.
    • Can you see my name Rangga Rifqi Pratama on the payload section?
  • Wait what ? then what’s the point if anyone can see the information ?
    • Well, it is one of the CONS of Stateless Authentication. I will explain more later.
    • That’s why i’d suggest you that never ever put any sensitive information in the JWT payload. As for me, I usually put only the user’s ID. Well, sometimes i put the email as well for no reason.
  • If you want to be a hacker, You can construct your own JWT, put any info that you want there. But the last step is you need to use the same secret key that is used by the server to make the server accept your token. So, this secret key… is the key. Don’t ever let it to be spilled!

Conclusion

By looking at above’s condition, we know that Stateless authentication can solve some problems that Stateful Authentication has. But it comes with trade-off:

PROS:

  • Much much cheaper. We don’t need extra tools or computing resource to do this. We just need to rely on encryption library.
  • Very scalable. 100 servers ? no worries.
  • Easy to implement, no need to think about an extra DB layer.

CONS:

  • Less secure.
    • As you can see on the section above, if your token is compromised, the one who has your token can see the session’s information. If the token contains sensitive informations, then you’re f***ed.
  • If there are so much information stored in the token, the token will be fat. If it exceeds 4MB, then we can’t store it in the HttpOnly cookies, forcing us to store it in the browser’s Local Storage. And local storage is vulnerable to XSS attack.
    • XSS attack is a malicious javascript code that can be injected to the application to do malicious thing. This can be mitigated by ensuring that your frontend code can avoid XSS attack. So no user will be able to do this attack.
    • However, there’s another door can lead to XSS attack. Which is a 3rd party library installation. When you use Javascript for your Frontend app, you must have installed 3rd party libraries right, and if let’s say one of it gets compromised, means someone just pushed a malicious code to the library’s source code, it can affect your application as well. Because that malicious code will run if the library gets called by your app.
  • Also, the fatter it is can affect the size of the HTTP request.
  • If the server’s secret key gets leaked, then you’re f***ed…..very badly.
  • Bad UX when your token is expired. Everytime your token is expired, you gets redirected to the login screen.
    • This can be mitigated by returning another token on successful login called Refresh Token. I will explain about it on a separate article. Insya Allah
  • If your Main JWT token gets leaked, you can’t ask the server’s administrator to revoke it. Because they can’t do anything to the token once it has been given to you. You just need to rely on the token’s short expiry.
  • If your Refresh token gets leaked, then your’re f***ed. The attacker can pretend to be you for x amount of time, depending on the refresh token's expiration date.

When to Use Stateless Authentication

  • When you’re too lazy to implement stateful authentication
  • When you’re able to mitigate the security concern.
  • When you can foresee that your application is successful & needs to be scaled over time with a less headache.

The Grand Conclusion

Woah this is a long article.

As Master Oogway said,

There’s no right or wrong in software architecture. There’s only trade-offs

So, choose your trade-offs wisely ;)

Allright, that’s all I can say. I hope you find something useful here.

الى اللقاء

Reference:

© 2024 Rangga Rifqi Pratama. All rights reserved