‹ Back to Home

Sessions vs JWT vs OAuth - what should your app use?

Confused about login options? Learn when to use server sessions, JWTs, or Google OAuth — plus Argon2 password hashing and refresh tokens, explained the way a senior dev would.

Keerthika 7 min read
Follow on Google
Web Dev Sessions vs JWT vs OAuth - what should your app use? 7 min left Follow on Google

TamilTech AI summary

  • Use sessions for websites and short JWTs for APIs and mobile.
  • JWTs are readable postcards — never put secrets in the payload.
  • Hash with Argon2id, and rotate refresh tokens if you use them at all.

AI-assisted summary, checked by the TamilTech editorial team.

0:00
0:00
🔒 Listen is for subscribers. Subscribe

Most Tamil Nadu web apps—college ERPs, shop catalogues, admin panels—should use a server session stored in an HttpOnly cookie, not a JWT in the browser. JWTs work better for mobile clients and public APIs, and Google OAuth only confirms who you are before you still issue your own session. This article explains the trade-offs, how tokens actually work, password hashing, and the revoke problem campus interviewers love to ask.

  • Sessions on HttpOnly cookies fit most websites. JWTs fit APIs and mobile apps.
  • A JWT is signed, not secret. Anyone can read the payload.
  • Google OAuth proves identity. You still start your own session after that.
  • Hash passwords with Argon2id. Never MD5. Never plain SHA-256.
  • Keep access tokens short. Rotate refresh tokens, or skip them and use a server session.

What is authentication, in one line?

You know that hostel demo where someone opened the Application tab, copied a token, and became admin on a second laptop? That silence is authentication. Campus interviewers poke this first because it shows whether you shipped something real, or only followed a YouTube video.

Authentication is the check that this request belongs to a user you already know. Not a guessed id in the URL. Not a token a classmate edited on jwt.io.

Sessions, JWTs, Google buttons — those are only proofs of identity. Authorisation is the next door: can this user open /admin, or only /orders. Mix the two words in a panel and they stop taking notes.

Should your app use sessions or tokens?

Picture a small hotel near T. Nagar. Session login is the front desk diary. After the password check, the server stores "user 42 is in" and sends a random session id in a cookie. Every request, the browser sends that cookie. The server opens the diary. Want them out? Delete the row.

A token is a laminated pass in the guest's pocket. The kitchen does not call the desk. It reads the pass. Handy when Android, web, and a partner API all hit you. Painful when you must kill a stolen pass right now.

For a college ERP, a Flipkart-style catalogue, or an internal dashboard, use a server session and an HttpOnly, Secure, SameSite cookie. For a public API or React Native, issue short tokens. Putting a JWT in localStorage is not modern. It is how XSS steals the room key.

import express from "express";
import session from "express-session";

const app = express();

app.use(session({
  secret: process.env.SESSION_SECRET,
  resave: false,
  saveUninitialized: false,
  cookie: {
    httpOnly: true,
    secure: process.env.NODE_ENV === "production",
    sameSite: "lax",
    maxAge: 1000 * 60 * 60 * 8
  }
}));

app.post("/login", async function (req, res) {
  req.session.userId = 42;
  res.json({ ok: true });
});

Keep the session id away from JavaScript. HttpOnly exists so a stray script cannot lift the cookie.

Quick options if you hate reading essays:

OptionFitsRevoke a user
Server session + cookieWebsite, admin panelDelete the session row
JWT access tokenAPI, mobileHard unless you keep a blocklist
OAuth (Google)Social login buttonYou still control your own session

What sits inside a JWT?

Three Base64 chunks with dots between them: header, payload, signature. Paste one into jwt.io. You can read the user id in the clear. Signed is not encrypted. The payload is a postcard, not a sealed cover.

The signature is the only reason nobody can change role to admin and walk in. Keep the secret on the server. HS256 with a long random secret is fine for one API. RS256 if several services must verify without sharing that secret.

import { SignJWT, jwtVerify } from "jose";

const secret = new TextEncoder().encode(process.env.JWT_SECRET);

const token = await new SignJWT({ sub: "42", role: "user" })
  .setProtectedHeader({ alg: "HS256" })
  .setIssuedAt()
  .setExpirationTime("15m")
  .sign(secret);

const { payload } = await jwtVerify(token, secret);
console.log(payload.sub);

Fifteen minutes is a sane access-token life. No PAN, no phone, no card number in claims. If your code accepts alg none, you have left the hostel latch open.

How do you add Google login with OAuth?

OAuth is a permission slip. Login with Google is OpenID Connect sitting on that slip. User taps the button. Google shows the account picker. Your callback gets a one-time code. Your server swaps the code for a profile, finds or creates the user, then starts your own session.

Do not save Google's access token as "logged in" for six months. Do not put the client secret in a frontend env file that ships to Chrome.

import crypto from "node:crypto";

const params = new URLSearchParams({
  client_id: process.env.GOOGLE_CLIENT_ID,
  redirect_uri: "https://yourapp.in/auth/google/callback",
  response_type: "code",
  scope: "openid email profile",
  state: crypto.randomUUID()
});

res.redirect(
  "https://accounts.google.com/o/oauth2/v2/auth?" + params.toString()
);

On the callback, exchange the code on the server, read email and the stable Google user id, then insert your session. GPay-class apps offer federated login so they are not storing yet another password. Your class project can too. Still keep email-plus-password, and still hash those passwords. Not every teammate wants a college app tied to Google.

How should you hash passwords?

If you see MD5, SHA-1, or a plain SHA-256 of a password, close the repo. Those hashes are fast. Fast is what attackers want. You want slow and memory-hard.

Argon2id is the default for new work. bcrypt is acceptable on an older Express codebase. Let the library generate a unique salt. Do not concatenate salt123 yourself and call it cryptography.

import argon2 from "argon2";

const hash = await argon2.hash(plainPassword, {
  type: argon2.argon2id,
  memoryCost: 19456,
  timeCost: 2,
  parallelism: 1
});

const ok = await argon2.verify(hash, plainPassword);

Rate-limit /login and /forgot-password. A perfect hash with an open brute-force hole is still a bad night.

Why do refresh tokens exist?

A 15-minute access token is annoying in a long form. A 30-day JWT in localStorage is worse if XSS ever shows up.

Keep the access token short. Put the refresh token in an HttpOnly cookie, or the OS keychain on mobile. When access dies, the client asks for a new pair. Rotate: new refresh token, old one dead. If the dead one appears again, kill the whole family. That is how theft shows up.

A one-process college API does not need this. req.session is enough. Add refresh tokens when the SPA and the API are split, or when Play Store and web share one backend.

Product teams at places like Zoho, Freshworks, Razorpay and PhonePe will wait to hear when you would not use a JWT. Whiteboard rounds still ask you to sketch the three JWT parts. Campus interviews lose people on "I put JWT in localStorage because a blog said so." Extra moving parts cost time. A session cookie is complexity you do not pay.

Which mistakes get people into trouble?

Storing JWT in localStorage. Copying the signing secret as the string secret. No exp claim. Trusting userId from the JSON body after login. Logging full tokens in PM2. Turning off CSRF protection on cookie sessions, then wondering why a random page could post /transfer.

Another classic: using the Google id_token on the client only, never verifying it on the server. Hashing with SHA-256 plus a pepper you committed to Git. Keeping refresh tokens forever with no rotation and no reuse detection.

If you use cookies, set SameSite, Secure, HttpOnly. If you use Bearer tokens, send them only on HTTPS. A JWT in a non-HttpOnly cookie is the worst of each world.

What should you do now?

Pick one app you already have. Take login off localStorage. Put it on a session cookie, or a 15-minute JWT you actually verify. Hash every password with Argon2id. If you added Google, map google_sub to your users table and throw away any tutorial that stores Google's token as your session.

Practice task: build a tiny register/login in Express. Hash with Argon2id. After login, set an HttpOnly session cookie. Add one /api/profile route that reads req.session.userId. Then add a second route that accepts a 15-minute JWT instead. Revoke the session and watch which route still works. Write four lines on why. That is the viva answer.

Frequently asked questions

5

Is a JWT more secure than a session?

No. Security depends on storage, expiry, HTTPS and how you revoke access. For a normal browser app, an HttpOnly session cookie done right is often the safer, simpler choice.

Can I store a JWT in localStorage?

You can, but you should not. Any XSS script can read localStorage and steal the token. Prefer an HttpOnly cookie, or a short-lived token that never sits in JavaScript storage.

If I use Login with Google, do I still hash passwords?

Yes, if you also offer email and password. Google users have no password in your database. Email users still need Argon2id. OAuth does not replace hashing for the signups you collect yourself.

Do I need refresh tokens for a college project?

Usually no. A server session is simpler, easy to revoke, and easier to explain in a viva. Add refresh tokens when a SPA, mobile app and API must share login without a shared session store.

What do Indian interviewers actually want on JWT vs sessions?

When you would pick a session over a JWT, what the three JWT parts are, why the payload is not secret, and Argon2id or bcrypt instead of MD5. Saying localStorage because a blog said so is a fast way to lose the round.

Get tomorrow’s tech news on WhatsApp

One short update a day, free. Follow the TamilTech channel.

What do you think?

people reacted

Keerthika

TamilTech editorial team · 3,737 articles

Keerthika is an editor at TamilTech, the Tamil and English technology publication founded by Praveen Kumar S. She covers AI, smartphones, gadgets, EVs, startups and cybersecurity i...

More from Keerthika

Ask TamilTech on WhatsApp

Tech doubt? Ask in Tamil or English — our WhatsApp assistant answers from TamilTech articles in seconds.

Related stories

Comments (0)

| Supports **bold**, *italic*, `code`

Be the first to comment!

Next story TypeScript Generics and Utility Types: How to Type Real API Responses Without the Headache
TamilTech

TamilTech

Install app for faster access

Earn XP 🏆
WhatsApp
Notifications