How to Build Node.js Auth: Exploring Stateless vs Stateful auth

Authentication is one of the major component of any application you use , now am pretty sure you know why we need auth , let me tell you anyway : Authentication is like a bouncer for your app, making sure only the right people get in. It keeps your data safe and ensures users can access their accounts securely.

Now as a newbie developer if heard about stateful and stateless auth and you google up and reading this blogpost to know what exactly stateful and stateless auth are lets begin to know what exactly these auth systems are and how to build one ? (at the end).

What is Stateful Authentication?

Stateful authentication is a method where the server retains session state for each authenticated user. This typically involves storing session data on the server, such as a unique session token or ID for each user. When a user logs in, the server verifies their identity by checking this session ID, ensuring both authentication and proper authorization.

The Challenge of Session Management

One key drawback of stateful authentication is that if the session memory is deleted on the backend, the session ID held by the client becomes completely useless. Because of this limitation, stateful authentication is often used for shorter sessions.

In such cases, users may need to log in each time they access the application.To sustain this authentication system, we ultimately have to store and update tokens in a database. Each time a user logs in, a database call is required to validate their credentials. This can lead to a significant number of database read operations, increasing costs and resource consumption.

However there are still usecases for session based auth.

Use Cases for Stateful Authentication

Despite the above stated issues, some applications still rely on stateful authentication. A good example this is banking apps, which prioritize security. In these applications, users must validate their login information every time they access their accounts to ensure maximum security,this why you have login into yono app everytime you want to use it and it automatically logs you out [india specific example]

Advantages of Stateful Authentication

  • High Security: Each session has a unique session ID, making it difficult for unauthorized users to gain access.

  • Simplicity: The implementation and management of stateful authentication can be pretty straightforward.

Disadvantages of Stateful Authentication

  • Resource Intensive: As the number of logged-in users increases, so does the demand on server resources.

  • Limited Third-Party Integration: It can be challenging for third-party applications to utilize your credentials effectively.

Now lets look into Stateless Auth.

What is Stateless Authentication?

In contrast to stateful authentication, stateless authentication does not rely on the server to maintain session state. Instead, each request from a client contains all the necessary information to verify the user's identity and authorization. This method typically uses tokens like JSON Web Tokens (JWTs).

but How Stateless Authentication Works?

With stateless authentication, credentials(payload) are stored in tokens that are encrypted using a secret key this key btw can be decrypted by anyone if they have it So, even though anyone can peek at a JWT's payload since it's just base64 encoded, that doesn’t compromise security. The real magic is in the signature. If someone tries to mess with the token, the server will reject it because the signature won’t match. It’s like a tamper-proof seal!.

When the server receives a token, it verifies it against this secret key. If any changes are made to the token data (payload) without the secret key, the server will invalidate the token and deny access.

Cool now that we are done with the theory lets build a very simple jwt base auth system in express js which will have signup , signin and a simple auth middleware that allows only authenticated users to access “/protected” route .

# initiate a project by :

mkdir auth-app
cd auth-app
npm init 

#hit enter to everything that comes after npm init

once you are done with setting up the project folder lets install express and jwt and cookie parser

# inside auth-app , lets install express and jwt first

npm i express jsonwebtoken cookie-parser

once you install the express framework , lets create a js file to write our auth app by :

#[bash]
touch app.js

now we are done with all basics and setup lets write our auth app inside app.js :)

const express = require("express");
const fs = require("fs");
const cors = require("cors");
const jwt = require('jsonwebtoken');
const cookieParser = require('cookie-parser');
const JWT_SECRET= "#fhdnenc" // KEEP THIS IN .env file in real project due to security 
const app = express();
app.use(express.json());
app.use(cookieParser());
app.use(cors());

const users = [];

app.get("/", (req, res) => {
  res.send("Welcome to the auth app");
});

function tokengenerator({ payload }) {
  return jwt.sign(payload, JWT_SECRET, { expiresIn: '1h' }); // Use '1h' for clarity
}

app.post("/signup", (req, res) => {
  const { name, email, password } = req.body;
  if (!name || !email || !password) {
    return res.status(400).send("Please fill all fields");
  }

  const user = {
    name,
    email,
    password,
  };

  users.push(user);

  res.status(200).json({ message: "Signup successful", user: { name, email } });
});

app.post("/login", (req, res) => {
  const { email, password } = req.body;
  const user = users.find((user) => user.email === email && user.password === password);

  if (!user) {
    return res.status(400).send("Invalid email or password");
  }

  const token = tokengenerator({ payload: { name: user.name, email: user.email } });
  res.cookie("token", token); // Set the token as a cookie
  return res.status(200).json({ message: "Login successful" });
});

function authvalidator(req, res, next) {
  const token = req.cookies.token; // Retrieve token from cookies

  if (!token) {
    return res.status(401).send("Unauthorized");
  }

  jwt.verify(token, JWT_SECRET, (err, decoded) => {
    if (err) {
      return res.status(400).send("Invalid token");
    }

    req.user = decoded;
    next();
  });
}

app.get("/protected", authvalidator, (req, res) => {
  res.send(`Welcome ${req.user.name} to the protected page`);
});

// Save users periodically
setInterval(() => {
  fs.writeFileSync("data.json", JSON.stringify(users));
}, 3600 * 1000); // Save every hour

app.listen(4000, () => {
  console.log("Server is running on port 4000"); // Corrected port number
});

now lets run the auth-app by :

node app.js

or you can also configure your package.json like this

{
  "name": "express-auth",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "server": "node app.js" #custom 
  },
  "author": "",
  "license": "ISC",
  "description": "",
  "dependencies": {
    "cookie-parser": "^1.4.7",
    "cors": "^2.8.5",
    "express": "^4.21.1",
    "jsonwebtoken": "^9.0.2"
  }
}

and run the app like this

npm run server

in real world application we DONT store the jwt secret in the app.js neither write all the paths and token generator function in a single file for the shake of understanding i have written all the code in single file .

also you can test this app/ api using postman or thunderclient inside vscode.

by : anshumancdx

0
Subscribe to my newsletter

Read articles from Anshuman Praharaj directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Anshuman Praharaj
Anshuman Praharaj

Mostly MERN and Python Currently learning CS concepts and building things. more on narcissistic bio: full-stack web dev and co-organizer of Google Developer Group (GDG) On campus - at Birla Global University. I love building web applications and sharing knowledge with fellow tech enthusiasts.