Session‐Based Authentication and Authorization - sonuprajapati15/Authentication-Authorization GitHub Wiki

System Design: Session-Based Authentication and Authorization

1. Overview

Session-based authentication is a method where a server creates and manages user sessions after successful login. These sessions are typically stored in memory, a database, or a caching layer (e.g., Redis). Unlike token-based authentication (JWT), session-based authentication is stateful, meaning the server tracks session information.


2. Functional & Non-Functional Requirements

Functional Requirements

✅ Users can register and log in using credentials.
✅ Upon successful login, a session is created and stored on the server.
✅ Clients receive a session ID (stored in cookies) to authenticate future requests.
✅ Users can log out, invalidating the session.
✅ Session expiration and automatic renewal mechanisms.

Non-Functional Requirements

Security – Use secure cookies, prevent session hijacking (e.g., CSRF, XSS attacks).
Scalability – Session storage should support distributed architectures.
Performance – Optimize session retrieval using in-memory caching (e.g., Redis).
Availability – Sessions should persist across failures (consider database-backed storage).
Compliance – GDPR and data privacy considerations for session storage.


3. High-Level Design (HLD)

Architecture Components

  1. Client (Browser/App) – Sends login credentials, stores session cookie.
  2. Authentication Server – Handles login/logout, generates session IDs, and manages session storage.
  3. Session Store – Stores session data (in-memory cache like Redis or a database).
  4. Resource Server – Validates session IDs and grants access to protected resources.

Workflow

  1. User logs in – Sends credentials to the authentication server.
  2. Session Creation – Server validates credentials and creates a session (stores in Redis/DB).
  3. Session Cookie – A session ID is sent to the client in a secure, HTTP-only cookie.
  4. Authenticated Requests – The client includes the session cookie in future requests.
  5. Session Validation – The server checks session validity before granting access.
  6. Logout & Expiry – The user logs out, or the session expires, and it’s removed from storage.

4. Low-Level Design (LLD)

Database Schema

CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    username VARCHAR(255) UNIQUE NOT NULL,
    password_hash TEXT NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE sessions ( session_id UUID PRIMARY KEY, user_id INT REFERENCES users(id) ON DELETE CASCADE, expires_at TIMESTAMP NOT NULL );

API Endpoints

Method Endpoint Description
POST /login Authenticate user and start a session
GET /protected Access protected resources (requires session)
POST /logout Destroy the session

6. Diagrams

Flowchart – Session-Based Authentication Workflow

Session-Based Authentication Flow

View or edit this diagram in Whimsical.


7. Code Implementation (Node.js + Express + Redis)

1. Install Dependencies

npm install express express-session bcrypt redis connect-redis dotenv

2. Setup Express Server with Session Management

require("dotenv").config();
const express = require("express");
const session = require("express-session");
const RedisStore = require("connect-redis").default;
const redis = require("redis");
const bcrypt = require("bcrypt");

const app = express(); const redisClient = redis.createClient({ url: process.env.REDIS_URL });

app.use(express.json()); app.use( session({ store: new RedisStore({ client: redisClient }), secret: process.env.SESSION_SECRET, resave: false, saveUninitialized: false, cookie: { httpOnly: true, secure: false, maxAge: 30 * 60 * 1000 }, // 30 min expiry }) );

// Mock database const users = [{ id: 1, username: "user1", passwordHash: bcrypt.hashSync("password", 10) }];

// Login Route app.post("/login", async (req, res) => { const { username, password } = req.body; const user = users.find((u) => u.username === username);

if (!user || !(await bcrypt.compare(password, user.passwordHash))) { return res.status(401).json({ message: "Invalid credentials" }); }

req.session.userId = user.id; res.json({ message: "Login successful" }); });

// Protected Route app.get("/protected", (req, res) => { if (!req.session.userId) { return res.status(401).json({ message: "Unauthorized" }); } res.json({ message: "Access granted" }); });

// Logout Route app.post("/logout", (req, res) => { req.session.destroy(() => res.json({ message: "Logged out" })); });

app.listen(3000, () => console.log("Server running on port 3000"));


Session Storage Options

  • In-memory (Fast, non-persistent) – Redis, Memcached.
  • Database (Persistent, but slower) – PostgreSQL, MySQL.

Session Expiry Strategy

  • Fixed expiration (e.g., 30 minutes).
  • Sliding expiration (session refreshes on activity).
  • Manual revocation (e.g., logout or forced session termination).

5. Trade-offs & Scalability

Factor Trade-off
Scalability Stateful sessions require session replication or sticky sessions in load-balanced setups.
Security Secure cookies prevent access from JavaScript; CSRF protection is necessary.
Performance Redis improves session lookup times, but adds infrastructure complexity.
Persistence Storing sessions in a database ensures durability but reduces speed.

8. Conclusion

Session-based authentication is a stateful approach that requires careful session storage management. It is a great choice for monolithic applications and scenarios where security is a priority, but it has scalability challenges compared to token-based authentication (JWT).

⚠️ **GitHub.com Fallback** ⚠️