REST APIs & JSON

Design and consume RESTful APIs: resource naming, HTTP methods, status codes, authentication patterns, and API security basics.

Hard 70m 3 tasks
Prerequisites: Node.js & Express Basics

Learning Objectives

  • Explain REST architectural constraints
  • Design RESTful URL schemas and select correct HTTP methods
  • Implement API authentication with API keys and JWT
  • Understand CORS and how to configure it safely
  • Identify common API security vulnerabilities

REST Constraints

REST (Representational State Transfer) is an architectural style with 6 constraints:

  1. Client-Server — UI and data separated
  2. Stateless — each request self-contained (no server session)
  3. Cacheable — responses must define cacheability
  4. Uniform Interface — consistent resource URIs + HTTP methods
  5. Layered System — client can't tell if it's talking to origin or proxy
  6. Code on Demand (optional) — server can send executable code

Resource Design

# Good REST URL design
GET    /api/v1/scans               list all scans
POST   /api/v1/scans               create new scan
GET    /api/v1/scans/{id}          get scan by ID
PATCH  /api/v1/scans/{id}          update scan
DELETE /api/v1/scans/{id}          delete scan

GET    /api/v1/hosts/{ip}/ports    ports for a host
POST   /api/v1/hosts/{ip}/scan     trigger scan on host

# Bad URL design (actions in URL)
POST   /api/createScan            GET    /api/getScan?id=123        POST   /api/deleteScan            

HTTP Status Codes for APIs

Status Meaning When to use
200 OK Successful GET, PATCH
201 Created Successful POST (new resource)
204 No Content Successful DELETE
400 Bad Request Invalid input
401 Unauthorized Missing/invalid auth
403 Forbidden Auth OK but no permission
404 Not Found Resource doesn't exist
409 Conflict Duplicate resource
422 Unprocessable Entity Validation errors
429 Too Many Requests Rate limited
500 Internal Server Error Unexpected server error

API Authentication

API Key

GET /api/scans HTTP/1.1
Authorization: Bearer sk-abc123...
X-API-Key: sk-abc123...       (alternative)

JWT (JSON Web Token)

JWT structure: header.payload.signature

eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxMjN9.HMAC_SHA256
// Express JWT middleware
const jwt = require("jsonwebtoken");

function authMiddleware(req, res, next) {
  const token = req.headers.authorization?.split(" ")[1];
  if (!token) return res.status(401).json({ error: "No token" });

  try {
    const payload = jwt.verify(token, process.env.JWT_SECRET);
    req.user = payload;
    next();
  } catch (err) {
    res.status(401).json({ error: "Invalid token" });
  }
}

// Issue token on login
app.post("/auth/login", async (req, res) => {
  const { username, password } = req.body;
  const user = await validateUser(username, password);
  if (!user) return res.status(401).json({ error: "Invalid credentials" });

  const token = jwt.sign(
    { user_id: user.id, role: user.role },
    process.env.JWT_SECRET,
    { expiresIn: "1h" }
  );
  res.json({ token });
});

CORS Configuration

const cors = require("cors");

// Allow specific origins only
app.use(cors({
  origin: ["https://app.example.com", "https://staging.example.com"],
  methods: ["GET", "POST", "PATCH", "DELETE"],
  allowedHeaders: ["Content-Type", "Authorization"],
  credentials: true,
}));

// NEVER do this in production:
app.use(cors({ origin: "*", credentials: true }));  // INSECURE

Rate Limiting

const rateLimit = require("express-rate-limit");

const limiter = rateLimit({
  windowMs: 15 * 60 * 1000,  // 15 minutes
  max: 100,                    // 100 requests per window
  message: { error: "Too many requests, try again later" },
  standardHeaders: true,       // Return RateLimit-* headers
});

app.use("/api", limiter);

Common API Vulnerabilities (OWASP API Top 10)

# Vulnerability Example
1 Broken Object Level Auth GET /api/orders/123 — can access other users' orders
2 Broken Auth Weak JWT secret, no expiry
3 Broken Object Property Auth Mass assignment: user sets role=admin via body
4 Unrestricted Resource Use No rate limiting on expensive endpoints
5 Broken Function Level Auth /admin routes accessible without admin role
6 Unrestricted Access to Sensitive Flows No CAPTCHA on reset-password endpoint
7 SSRF fetch(req.body.url) fetches internal services
8 Security Misconfiguration CORS *, verbose error messages in prod
9 Improper Inventory Management Old v1 API still accessible and unpatched
10 Unsafe Consumption of APIs Trusting 3rd party API data without validation

Mini Project – Versioned Scan API

const express = require("express");
const rateLimit = require("express-rate-limit");
const app = express();
app.use(express.json());

const scans = new Map();

const limiter = rateLimit({ windowMs: 60000, max: 30 });

function auth(req, res, next) {
  if (req.headers["x-api-key"] !== process.env.API_KEY) {
    return res.status(401).json({ error: "Unauthorized" });
  }
  next();
}

const v1 = express.Router();

v1.use(limiter);
v1.use(auth);

v1.get("/scans", (req, res) => {
  res.json({ scans: [...scans.values()] });
});

v1.post("/scans", (req, res) => {
  const { host } = req.body;
  if (!host) return res.status(400).json({ error: "host required" });
  const id = Date.now().toString();
  scans.set(id, { id, host, status: "queued" });
  res.status(201).json(scans.get(id));
});

v1.get("/scans/:id", (req, res) => {
  const scan = scans.get(req.params.id);
  if (!scan) return res.status(404).json({ error: "Not found" });
  res.json(scan);
});

app.use("/api/v1", v1);
app.listen(3000, () => console.log("API on :3000"));

Design REST endpoints for a vulnerability tracker: create, list, get, update, delete vulnerabilities. Also design endpoints for: mark vuln as fixed, list vulns by severity, get vuln history. Write them in a table: METHOD | PATH | Description.

✦ Answer the questions to complete this task

What HTTP method updates a partial resource (not the whole thing)?

What status code should a successful POST (resource created) return?

Extend the Express scan API with JWT auth: POST /auth/login returns a JWT token (use jsonwebtoken package). Protect all /api/v1 routes with the auth middleware. Test: get a token, use it in Authorization: Bearer header, try without token.

✦ Answer the questions to complete this task

What are the three parts of a JWT separated by dots?

Where should JWT secrets be stored in Node.js?

Add express-rate-limit with 10 requests/minute on the scan endpoints. Add CORS allowing only http://localhost:3000. Test rate limit by sending 11 requests quickly with a loop. Verify 429 on the 11th.

✦ Answer the questions to complete this task

What HTTP status code means 'Too Many Requests'?

💪 Exercises & Challenges

📝 MCQ Medium +20 XP

REST APIs & JSON MCQ

REST APIs & JSON MCQ

Start →
⚙️ Practical Medium +30 XP

Full Authenticated REST API

Full Authenticated REST API

Start →
🚩 Challenge Hard +50 XP

BOLA Flag

BOLA Flag

Start →