Full-Stack Playground

Live Demo

An interactive app covering every layer of full-stack web development. Learn by doing.

TOTAL TASKS
0
↑ stored in memory DB
COMPLETED
0
tasks finished
API CALLS
0
REST requests made
SESSION
0s
time active

šŸ—ŗ What You'll Learn

šŸ“‹
Frontend + CRUD
Forms, DOM manipulation, REST calls
→
⚔
REST API Design
Endpoints, methods, status codes, JSON
→
šŸ—„
Database & SQL
Schema, queries, relations, live SQL runner
→
šŸ”
Auth & JWT
Tokens, sessions, hashing, cookies
→
šŸ›”
Security & Bug Bounty
XSS, SQLi, IDOR, CSRF explained
→
šŸ–„
Server & HTTP
Headers, CORS, cookies, Node.js
→

šŸ” Request Lifecycle

Every web request travels through these layers. Understanding this is the foundation of bug bounty.

BROWSER User fills form → JS fires fetch() → HTTP request created
↓
NETWORK DNS → TCP handshake → TLS → Packet routing
↓
SERVER Router → Middleware → Auth check → Controller
↓
DATABASE SQL query → fetch rows → return JSON
↓
RESPONSE HTTP 200 + JSON → JS updates DOM
01

Frontend + CRUD Operations

This simulates how a real app works: form input → API call → database write → UI update. The "database" here is JavaScript's in-memory array.

Create Task (POST /api/tasks)

JS — FETCH API
const response = await fetch('/api/tasks', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json',
    'Authorization': `Bearer ${token}` },
  body: JSON.stringify({ title, priority })
});
const data = await response.json();
// data = { id: 42, title: '...', createdAt: '...' }

Task List (GET /api/tasks)

No tasks yet. Create one on the left ↑

HTTP Response Codes You'll See

200
OK — request succeeded
201
Created — POST succeeded
401
Unauthorized — no/bad token
403
Forbidden — token valid, no access
404
Not Found — resource missing
422
Unprocessable — bad input data
500
Server Error — backend crashed
302
Redirect — move to new URL
02

REST API Design

REST (Representational State Transfer) is a design pattern for building APIs. Click any endpoint to simulate the request and see the response structure.

TaskFlow API Endpoints

Response Viewer

← Click an endpoint to simulate a request

RESTful Principles

NounsURLs describe resources, not actions: /tasks not /getTasks
VerbsHTTP methods do the work: GET=read, POST=create, PUT=update, DELETE=remove
StateServer is stateless — each request must carry auth (Bearer token or cookie)
JSONStandard data format for request bodies and responses

Node.js / Express Route Implementations

NODE.JS — EXPRESS
const express = require('express');
const router = express.Router();

// GET all tasks — requires auth middleware
router.get('/tasks', authenticate, async (req, res) => {
  const tasks = await db.query('SELECT * FROM tasks WHERE user_id=$1', [req.user.id]);
  res.json({ tasks: tasks.rows });
});

// POST create — validates input
router.post('/tasks', authenticate, async (req, res) => {
  const { title, priority } = req.body;
  if (!title) return res.status(422).json({ error: 'Title required' });
  const task = await db.query('INSERT INTO tasks(title,priority,user_id) VALUES($1,$2,$3) RETURNING *', [title, priority, req.user.id]);
  res.status(201).json(task.rows[0]);
});

// DELETE — checks ownership (prevents IDOR)
router.delete('/tasks/:id', authenticate, async (req, res) => {
  const task = await db.query('DELETE FROM tasks WHERE id=$1 AND user_id=$2 RETURNING *', [req.params.id, req.user.id]);
  if (!task.rows.length) return res.status(404).json({ error: 'Not found' });
  res.json({ deleted: true });
});
03

Database & SQL

Databases store persistent data. Understanding schema design and SQL is critical — it's where SQL Injection vulnerabilities live.

Schema — Tables

šŸ—„users
idSERIALPK auto-increment
usernameVARCHAR(50)UNIQUE NOT NULL
emailVARCHAR(100)UNIQUE NOT NULL
password_hashVARCHAR(60)bcrypt hash — never plain text!
roleENUM'user' | 'admin'
created_atTIMESTAMPDEFAULT NOW()
šŸ“‹tasks
idSERIALPK
user_idINTEGERFK → users.id (ownership!)
titleVARCHAR(200)NOT NULL
descriptionTEXTnullable
priorityENUM'low' | 'medium' | 'high'
statusENUM'todo' | 'done'
created_atTIMESTAMPDEFAULT NOW()

SQL Query Runner

Practice SQL queries against the in-memory task database.

Key SQL Concepts for Bug Bounty

Primary Keys
Unique identifier for each row. In bug bounty: incrementing IDs (1, 2, 3…) are vulnerable to IDOR — you can guess other users' resource IDs.
Foreign Keys
Links rows across tables. tasks.user_id → users.id. If the server doesn't check this on DELETE/GET, attacker can access other users' tasks.
Parameterized Queries
The defense against SQLi. Pass user input as $1 parameter, never concatenate strings directly into SQL.
04

Authentication & JWT

Auth is one of the most bug-bounty-rich areas. Understand how it works to find where it breaks.

Login Simulator

How JWT Works

1 User submits username + password to /api/login
2 Server checks password against bcrypt hash in DB (never compare plaintext!)
3 Server creates JWT: header.payload.signature — payload contains user ID, role, expiry
4 Client stores JWT in localStorage or HttpOnly cookie
5 Every future request sends JWT in Authorization: Bearer <token> header
6 Server verifies signature using secret key — if tampered, signature fails

Bug Bounty Auth Weaknesses

ā—alg: none — some servers accept JWTs with no signature if algorithm is "none"
ā—Weak secret — if JWT secret is "secret" or "password", it can be brute-forced
ā—No expiry — tokens without exp claim never expire, stolen tokens work forever
ā—localStorage XSS — if JWT is in localStorage, XSS can steal it
05

Security Vulnerabilities (Bug Bounty)

The OWASP Top 10 are the most common web vulnerabilities. Click each to expand the explanation and see where it hides in this app.

Security Headers Checker

HTTP response headers can prevent many attacks. Check what a server should send:

06

Server & HTTP Internals

Understand the server layer — where middleware, CORS, cookies, and request parsing happen.

Interactive HTTP Terminal

Simulate curl commands. Type commands below.

$

Node.js Server Structure

NODE.JS — SERVER SETUP
const express = require('express');
const app = express();

// 1. Parse JSON bodies
app.use(express.json());

// 2. CORS — allow specific origins
app.use(cors({ origin: 'https://myapp.com', credentials: true }));

// 3. Rate limiting (prevents brute force)
app.use(rateLimit({ windowMs: 15*60000, max: 100 }));

// 4. Auth middleware — verify JWT
function authenticate(req, res, next) {
  const token = req.headers.authorization?.split(' ')[1];
  if (!token) return res.status(401).json({ error: 'No token' });
  req.user = jwt.verify(token, process.env.JWT_SECRET);
  next();
}

app.listen(3000);

Middleware Stack

Request In
body-parser
cors check
rate limiter
authenticate()
route handler
Response Out