FinalYearKitFinalYearKit
All posts
Architecture14 min read·

JWT authentication in MERN final year projects — tokens, roles, and viva answers

How Indian B.Tech teams should implement JWT login, middleware, roles, and token storage — plus viva answers examiners actually ask.

R

Rajan

Founder & kit engineer

Almost every MERN final year project in Indian colleges ships with “JWT authentication” written somewhere on slide 3. Panels have heard the acronym hundreds of times. What separates a passable demo from a strong viva is whether you can explain the full path from login form to protected controller, justify where the token lives, and show that authorization is enforced on the server — not only by hiding menu items in React.

This guide is written for B.Tech / BE students defending kits like Library Management System or MERN Ecommerce. The same spine appears in hotel, restaurant, hospital, and fleet kits: bcrypt passwords, signed tokens, Express middleware, and role checks.

Why JWT shows up in every MERN kit

A typical college deployment separates a Vite/React frontend from an Express API. Sessions that rely on sticky server memory break that model. JSON Web Tokens travel with each request, carry a small claim set (userId, role, maybe email), and verify with a secret without a round-trip to a session store. That is why FinalYearKit MERN domains standardize on JWT rather than inventing a new auth story per project.

Say this opening pitch in under 40 seconds:

“We use JWT for authentication. On login, bcrypt verifies the password; the server signs a token with user id and role. Protected routes run auth middleware first, then optional requireRole. The React app stores the token and sends it on API calls, but authorization decisions always happen on Express.”

Stop there. Do not recite the JWT Wikipedia page.

Anatomy of a token you can draw on the whiteboard

A JWT has three Base64url parts: header, payload, signature. Header names the algorithm (usually HS256 in student projects). Payload holds claims. Signature proves the payload was not altered given the server secret.

Claims worth putting in your report diagram:

  • ▸sub or userId — who is authenticated
  • ▸role — coarse authorization hint
  • ▸iat / exp — issued-at and expiry

Do not put passwords, Aadhaar numbers, or full medical history in the payload. Anything in the payload is readable by anyone who holds the token; only the signature is secret-protected.

Secret management

JWT_SECRET lives in .env, never in GitHub, never hardcoded in slides. For viva, open your .env.example (without the real secret) and say “production secret is injected by the host.” If the panel asks about rotation, short expiry plus re-login is an honest undergraduate answer; full key rotation pipelines are out of scope unless you built them.

Login sequence — memorize this order

  1. ▸Client POST /api/auth/login with email and password.
  2. ▸Server finds user by email.
  3. ▸bcrypt.compare(plain, passwordHash).
  4. ▸On success, jwt.sign({ userId, role }, secret, { expiresIn }).
  5. ▸Response returns token (and maybe a safe user object without hash).
  6. ▸Client stores token and redirects by role.

Register follows the same idea with bcrypt.hash before insert. Unique email index prevents duplicate accounts — mention that when asked about database constraints.

Password hashing talking points

bcrypt with a reasonable cost factor (your code’s saltRounds) is enough for final year. Never store plaintext. Never log request bodies that contain passwords. If asked “why not MD5?”, answer: MD5 is fast and unsalted hashes are vulnerable to rainbow tables; bcrypt is intentionally slow and salted.

Middleware order — a favorite trick question

Correct mental model for Express:

CORS → JSON body parser → auth → requireRole → controller.

If requireRole runs before auth, there is no req.user. If a controller is mounted without middleware, a student who knows the URL can hit it from Postman even when the React menu hides the button. Your viva line must be: “UI hiding is UX; middleware is security.”

What auth middleware does

Extract Bearer token from Authorization header (or cookie if that is your design). jwt.verify. Attach req.user. On failure: 401 Unauthorized. On success but wrong role: 403 Forbidden. Mixing up 401 and 403 is a common soft mark hit — rehearse the difference once.

Roles vs authentication

Authentication answers “who are you?” Authorization answers “are you allowed?” JWT proves identity and can carry a role claim, but your permission matrix still belongs in middleware or policy helpers.

Example matrix for a library kit (rows = roles, columns = actions):

| Action | Member | Librarian | Admin | | --- | --- | --- | --- | | Browse books | yes | yes | yes | | Issue loan | no | yes | yes | | View audit | no | no | yes | | Delete user | no | no | yes |

Draw the same idea for ecommerce (customer / seller / admin) or hospital (patient / doctor / receptionist / admin). Consistency between report Chapter 4, slides, and code role strings matters more than fancy RBAC libraries.

For a deeper RBAC walkthrough in a concrete domain, see Library Management System viva — RBAC, audit log, and generic CRUD.

Where should the token live?

Indian viva panels often ask: localStorage or httpOnly cookie?

localStorage: easy with SPAs; readable by any XSS script on your origin.
httpOnly cookie: not reachable from JavaScript; needs CSRF strategy if cookie is sent automatically on same-site requests.

Either answer is acceptable if you name the tradeoff and match your implementation. Do not claim “localStorage is perfectly safe.” Do not claim “cookies solve everything” if you never set SameSite or CSRF protections.

Axios / fetch pattern

Centralize an API client that attaches Authorization: Bearer ${token}. On 401, clear storage and redirect to login. That single interceptor prevents half of “random demo failures” when tokens expire mid-presentation.

Expiry, refresh, and logout

Undergraduate kits usually use access tokens with expiry of 1 day or 7 days and no refresh-token rotation. That is fine if you say so. Logout clears client storage; the old JWT remains valid until expiry unless you built a denylist. Honest answer: “We use short-lived tokens and client logout; server-side revocation is future work.” Pretending you have Redis revocation when the repo does not will get you caught in five minutes.

Clock skew and IST demos

Lab machines and Atlas-hosted APIs may disagree on time. If tokens “randomly” fail at the venue, check system clock and exp. Mentioning this as a debugging story sounds more real than claiming perfect reliability.

Protected routes on the React side

React Router guards (or equivalent) read auth context and redirect unauthenticated users. Role-based route wrappers hide admin pages from members. Emphasize again: these guards improve UX and reduce confusion; they are not the security boundary.

Context shape worth defending:

{ user, token, login(), logout(), isAuthenticated }

Avoid storing the password hash anywhere on the client. Strip it in the login response serializer.

Common viva Q&A bank

Q: Difference between JWT and session cookies?
A: Sessions keep state on the server (or session store); JWT is self-contained and verified by signature. JWT fits separate frontend/backend hosts common in our deployment.

Q: Can the user edit the role inside the token?
A: They can alter the payload bytes, but the signature will fail verification. Without the secret they cannot mint a valid admin token.

Q: Why include role in the token instead of loading it every request?
A: Fewer DB hits; role changes may lag until re-login — we accept that tradeoff. Critical admin actions can re-fetch the user document if needed.

Q: What algorithm do you use?
A: HS256 with a server secret (state what jsonwebtoken uses in your code). Asymmetric RS256 is possible but uncommon in our kits.

Q: How do you test auth?
A: Login happy path; wrong password 401; expired token 401; member hitting admin route 403; missing header 401. Put these in Chapter 6 test cases.

Q: CORS and credentials?
A: Frontend origin allowlisted; if cookies are used, credentials: true and matching CORS config. For Bearer headers, CORS still must allow the Authorization header.

Security checklist for Chapter 6 / demo day

  • ▸[ ] bcrypt on register/login only — never compare plaintext in DB
  • ▸[ ] JWT secret only from env
  • ▸[ ] Auth middleware on every sensitive router
  • ▸[ ] Role middleware matches permission matrix
  • ▸[ ] Password field excluded from API responses
  • ▸[ ] HTTPS note for production (college Wi-Fi demos may still be HTTP localhost — say that)
  • ▸[ ] Seed users with known passwords for viva, not production passwords committed to git

How JWT connects to domain logic

Auth is the door; domain rules are the rooms. In ecommerce, a customer JWT must not update another user’s orders — check req.user.id against order.userId. In library loans, librarian role is required to issue. In hotel booking, guest creates bookings for self; front-desk manages all. JWT gets you identity; controllers encode ownership checks.

When money appears (Razorpay flows, invoice totals), never trust client-supplied prices even for authenticated users. Auth proves who; server-side pricing proves integrity. Cross-link that idea with ecommerce viva prep in Razorpay in MERN ecommerce viva if payments are in scope.

Report and slide placement

Chapter 3 / 4: sequence diagram Login → JWT → middleware → controller.
Chapter 5: implementation screenshots of middleware files.
Chapter 6: 401/403 test table.
Slide: one sequence, one permission matrix — not six buzzword bullets.

Avoid filling slides with “secure, scalable, robust.” Examiners grade specificity.

Failure demos that raise marks

Show Postman (or Thunder Client) calling an admin route without a token → 401. Then with a member token → 403. Then with admin token → 200. Narrate status codes. This three-shot demo often lands harder than a polished UI walkthrough because it proves you understand the boundary.

Second failure: tamper with the token string in DevTools and reload — API should reject. Third: delete token and hit a protected page — redirect to login.

Deployment notes for Indian college labs

Many teams use Render/Railway/Vercel-style hosts plus MongoDB Atlas. Remember:

  • ▸Set JWT_SECRET in the host dashboard
  • ▸Allowlist the viva venue IP on Atlas if needed
  • ▸Keep token expiry long enough that a 20-minute viva does not log you out mid-demo (or have seed re-login ready)
  • ▸Mirror env vars on both API and any SSR host if split

Localhost demos are fine; say “same JWT flow in production with HTTPS and env secrets.”

What not to claim

  • ▸“JWT is encrypted” (it is signed; payload is readable)
  • ▸“Nobody can ever steal the token” (XSS and device theft exist)
  • ▸“We use OAuth2 / OpenID fully” unless you integrated Google login for real
  • ▸“Blockchain-based auth” for a college library app

Honesty beats buzzwords. Panels in Indian universities reward students who know their own repo.

Register, login, and “me” endpoints

A clean auth module usually exposes:

  • ▸POST /api/auth/register — validate email/password strength, hash, insert, optionally auto-login
  • ▸POST /api/auth/login — verify, sign JWT
  • ▸GET /api/auth/me — requires auth, returns current user profile without hash

/me is underrated in vivas. It proves the token maps to a live user document (role changes, deactivated accounts) instead of trusting JWT claims forever. Some teams re-fetch /me on app load before rendering role dashboards. If the user was banned (isActive: false), reject even if the signature is valid.

Password policy for academic scope

Require minimum length (8+), reject empty strings, optionally require one number. Do not build a full NIST complexity UI unless your SRS demands it. Document the rule once in Chapter 3 and validate on both client and server. Client-only checks are not enough — Postman will skip them.

Email normalization

Store emails lowercased and trimmed. Otherwise Raj@College.edu and raj@college.edu become two accounts and your unique index looks “broken” in viva. Mention this as a small but real data-quality decision.

ObjectId ownership checks beyond roles

Role middleware answers “is this a librarian?” Ownership answers “is this their loan / order / booking?” Patterns:

if (String(order.userId) !== String(req.user.id) && req.user.role !== 'admin') {
  return res.status(403).json({ message: 'Forbidden' });
}

Without this, any authenticated customer who learns another order id can read it. Panels who have graded ecommerce kits often jump straight here after you mention JWT. Practice the sentence: “Authentication identifies the caller; ownership checks bind resources to that caller.”

Hospital and library kits need the same idea for patient notes and member loan history. Cross-link mentally to domain posts when your project is medical or catalog-heavy.

Rate limiting and brute force (honest scope)

Undergraduate APIs are often wide open to password spraying. A minimal answer that still sounds responsible:

  • ▸Mention express-rate-limit on /login if you added it
  • ▸If not implemented, list it under future work with one sentence on why login endpoints are sensitive
  • ▸Never invent a captcha you did not ship

Account lockout after N failures is optional depth. Prefer one real control over three fake ones.

Cookies deep dive if your kit uses them

If you set JWT in an httpOnly cookie:

  • ▸Secure in production HTTPS
  • ▸SameSite=Lax or Strict depending on cross-site needs
  • ▸Path and domain aligned with API host
  • ▸Logout clears the cookie server-side (res.clearCookie) as well as client state

If frontend and API origins differ, discuss CORS credentials carefully. Many student demos break the day they move from localhost:5173 ↔ localhost:5000 to deployed URLs — rehearse that configuration once before external viva.

Mapping auth to the eight-chapter report

Indian B.Tech reports often follow a fixed chapter skeleton. Place auth deliberately:

  • ▸Introduction: “secure role-based access” as an objective, not a buzzword pile
  • ▸Requirements: login, logout, role permissions as shall-statements
  • ▸Design: sequence + middleware pipeline + matrix
  • ▸Implementation: file paths (auth.middleware.js, requireRole.js)
  • ▸Testing: 401/403/200 table
  • ▸Conclusion: limitations (no refresh rotation, no OAuth) as future work

If your department uses the common eight-chapter layout, align headings with eight chapter report structure so examiners find the JWT story where they expect it.

Team viva coordination

When two or three teammates present, decide who owns the auth explanation. The teammate who coded middleware should answer signature and role questions; the teammate who built React guards should explain UX redirects without contradicting “server is the boundary.” Conflicting answers (“token is in cookies” vs “we use localStorage”) are a frequent group-viva failure mode. Write the chosen storage approach on a sticky note for everyone.

Mini glossary for last-minute revision

  • ▸Claim: field inside JWT payload
  • ▸Bearer token: scheme sending JWT in Authorization header
  • ▸401: not authenticated
  • ▸403: authenticated but not allowed
  • ▸RBAC: role-based access control
  • ▸bcrypt: password hashing algorithm
  • ▸Expiry (exp): time after which verify fails

Read this glossary aloud once the morning of viva. Short words beat long speeches when you are nervous.

Related architecture reading

Pair this post with common viva mistakes in CS projects so you do not undermine a solid JWT story with a silent demo or mismatched role names.

Project kits that use this pattern

Takeaway: Defend JWT as a signed identity carrier, put real authorization in Express middleware and ownership checks, and rehearse 401/403 demos — that combination is what Indian B.Tech panels mark, not the acronym alone.

Ready to work on your own project?

We build complete project kits with source code, report, slides, and viva prep — message us on WhatsApp to get started.

Ask about this on WhatsApp
Message us