# 04. Networking, Storage, and Security

At this point in the handbook, you know how JavaScript runs and how browsers render. The next question is: how does a browser app talk to the outside world, keep data around, and stay safe while doing it?

This chapter covers that boundary.

Networking, storage, and security are deeply connected in browsers. A request is not just "send bytes to a server." It is constrained by origin policy, cookies, credential rules, caching, and user safety. Storage is not just "save some data." It is tied to persistence, quota, privacy, and attack surface. Authentication is not just a backend concern because the browser decides which credentials are attached automatically and which APIs are exposed to JavaScript.

This file connects directly to:

- [02-javascript-in-the-browser.md](./02-javascript-in-the-browser.md), which introduced browser Web APIs such as `fetch` and storage
- [03-dom-event-loop-rendering.md](./03-dom-event-loop-rendering.md), because fetch completion and storage use still re-enter JavaScript through the same scheduling model
- [05-real-world-architecture-patterns.md](./05-real-world-architecture-patterns.md), where these primitives become data-layer and deployment decisions

## HTTP and HTTPS From the Browser's Point of View

Backend engineers often describe HTTP in server-centric terms: routes, handlers, payloads, proxies. Frontend engineers need a browser-centric model too.

From a browser page's perspective, HTTP is how it gets almost everything:

- the initial HTML document
- JavaScript bundles or modules
- CSS files
- images, fonts, and media
- API data for in-page updates

So HTTP is not a side system. It is the bloodstream of the web page.

### What the Browser Actually Cares About

When the browser makes or receives an HTTP request, it is not only tracking the URL and body. It also cares about:

- origin and security policy
- request method and headers
- cacheability
- cookies and credentials
- redirect behavior
- content type and decoding
- connection reuse and protocol version
- whether the response is allowed to reach page JavaScript

That last point matters. A server can return bytes, but the browser still decides whether page code is allowed to see them under the web security model.

### Why HTTPS Matters So Much in Browsers

HTTPS is HTTP over TLS. The practical browser reason is not just privacy in the abstract. It is trust and integrity.

Without HTTPS, an attacker on the network path could:

- read traffic
- modify scripts in transit
- inject hostile content
- steal cookies without proper protection

If an attacker can alter your JavaScript bundle in transit, they effectively own your page. That is why secure transport is foundational to browser security rather than a nice extra.

Modern browser features also increasingly assume secure contexts. Many APIs either require or strongly prefer HTTPS because the browser only wants to expose powerful capabilities in a transport it can trust more.

## Request Types the Browser Makes

From the browser's perspective, not all requests are the same.

### Navigation Requests

These load a new document. Typing a URL in the address bar or clicking a normal link usually triggers navigation.

### Subresource Requests

These fetch supporting assets for a page:

- scripts
- stylesheets
- images
- fonts

### Programmatic Requests

These are created by JavaScript using APIs such as `fetch` or `XMLHttpRequest`. They are central to single-page apps because they let the UI update without a full-page reload.

This distinction matters because browsers handle navigation, rendering, and security policies differently across these request categories.

## The Fetch Lifecycle

`fetch` looks simple in code, but a lot happens between `await fetch(...)` and your response handler.

```js
const response = await fetch("/api/products", {
  method: "GET",
  credentials: "include"
});

const data = await response.json();
```

### High-Level Fetch Request Lifecycle

```mermaid
flowchart LR
    A[JavaScript calls fetch] --> B[Browser validates request options]
    B --> C[Check service worker and caches]
    C --> D[Apply origin and CORS rules]
    D --> E[Reuse or create network connection]
    E --> F[Send HTTP request]
    F --> G[Receive response headers and body]
    G --> H[Resolve fetch promise with Response object]
    H --> I[JavaScript consumes body stream or parsed data]
```

### Step-by-Step Intuition

1. JavaScript creates a request description.
2. The browser checks request mode, credentials settings, headers, and policy restrictions.
3. A service worker may intercept the request if one is active.
4. The browser may consult caches before going to the network.
5. Security rules such as same-origin policy and CORS are applied.
6. The browser uses an existing connection or establishes a new one.
7. Response headers arrive, then body data streams in.
8. The fetch promise resolves once the response object is available.
9. Later body-reading methods such as `response.json()` perform additional async work.

### Important Subtlety: `fetch` Resolves on HTTP Errors Too

`fetch` rejects on network-level failure, abort, or some policy failures. But a normal HTTP error such as `404` or `500` still produces a response object.

That is why this is common:

```js
const response = await fetch("/api/user");

if (!response.ok) {
  throw new Error(`Request failed: ${response.status}`);
}
```

This behavior makes sense once you realize that HTTP error status is still a valid HTTP response, not a transport failure.

### Streams and Why the Browser Works This Way

Response bodies are often stream-oriented because browsers do not want to wait for the entire payload to be fully buffered before exposing data. Streaming improves memory efficiency and latency for large responses.

This becomes especially important for:

- large downloads
- video and media delivery
- streaming server responses
- progressively rendered HTML or data pipelines

## Same-Origin Policy: The Browser's Core Isolation Rule

The same-origin policy is one of the web's foundational security rules.

At a useful level, an origin is a combination of:

- scheme, such as `http` or `https`
- host, such as `app.example.com`
- port, such as `443`

If two resources differ in one of those, they are different origins.

### Why This Policy Exists

Imagine you are logged into your bank in one browser tab and visit a malicious site in another. Without origin isolation, that malicious page could simply read sensitive data from the bank site using your browser's authenticated session.

The same-origin policy exists to prevent one origin's page JavaScript from freely reading data from another origin.

This is one of the most important "why it works this way" topics in browser engineering. The browser is not trying to make developers suffer. It is acting as a guard between mutually untrusting websites loaded by the same user.

## CORS: Controlled Relaxation of Same-Origin Restrictions

CORS, or Cross-Origin Resource Sharing, is a browser mechanism that lets servers explicitly say which cross-origin requests are allowed.

### Deep Intuition

Same-origin policy says: "pages cannot freely read responses from other origins."

CORS adds: "unless the target server explicitly opts in under defined rules."

### What CORS Is and Is Not

- CORS is enforced by browsers.
- CORS is mainly about whether frontend JavaScript can access the response.
- CORS does not stop server-to-server requests because there is no browser enforcing the rule there.
- CORS is not an authentication mechanism.

### Simple Request vs Preflighted Request

Some cross-origin requests can be sent directly, and the browser checks whether the response includes the right CORS headers.

Other requests require a preflight: an `OPTIONS` request sent first to ask the server what is allowed.

Triggers for preflight commonly include:

- non-simple methods such as `PUT` or `DELETE`
- certain custom headers
- certain content types outside the simple set

### CORS Flow

```mermaid
sequenceDiagram
    participant App as Browser App
    participant Browser as Browser Security Layer
    participant API as API Server

    App->>Browser: fetch cross-origin resource
    alt preflight required
        Browser->>API: OPTIONS preflight
        API-->>Browser: Access-Control-* headers
    end
    Browser->>API: actual request
    API-->>Browser: response with CORS headers
    Browser-->>App: expose response only if policy allows
```

### Credentials and CORS

Cross-origin requests become trickier when cookies or other credentials are involved.

If credentials are included:

- the browser requires tighter CORS rules
- wildcard origin settings usually cannot be used in the same permissive way
- server intent must be explicit

This is deliberate. If authenticated browser requests could be casually shared across origins, cross-site data leaks would be much easier.

## Cookies, `localStorage`, `sessionStorage`, and IndexedDB

Browser storage is not one thing. Different storage mechanisms exist because the web needs different tradeoffs.

### Storage Comparison

| Storage | Lifetime | Sent automatically with requests | Typical size | Best use |
| --- | --- | --- | --- | --- |
| Cookies | configurable expiry or session | Yes, depending on scope and rules | small | session/auth and server-visible state |
| `localStorage` | persists until cleared | No | small-ish | simple client-only persistence |
| `sessionStorage` | per-tab session | No | small-ish | temporary tab-scoped data |
| IndexedDB | persistent | No | much larger | structured app data and offline caching |

### Cookies

Cookies are small key-value pieces of data associated with requests to matching origins and paths.

Why cookies are special:

- the browser can attach them automatically to matching requests
- servers can set them using `Set-Cookie`
- security attributes such as `HttpOnly`, `Secure`, and `SameSite` affect how they behave

That automatic attachment makes cookies powerful for authentication, but also sensitive from a security standpoint.

### `localStorage`

`localStorage` is a simple synchronous key-value API accessible from JavaScript.

Why it is popular:

- easy to use
- persistent across page reloads
- fine for small client-only preferences

Why it should not be overused:

- synchronous API can block if abused
- string-only interface is primitive
- available to JavaScript, so any successful XSS can read it

### `sessionStorage`

`sessionStorage` is similar to `localStorage` but scoped to the lifetime of a tab or page session.

Useful for:

- temporary wizard progress
- transient UI state that should not survive a full long-term session

### IndexedDB

IndexedDB is the browser's serious client-side database option.

It exists because richer apps need more than tiny string storage:

- offline data
- larger structured records
- indexes and queries
- versioned schema upgrades

If `localStorage` is a sticky note, IndexedDB is a filing cabinet.

### Storage Landscape Diagram

```mermaid
flowchart TD
    A[Browser App] --> B[Cookies]
    A --> C[localStorage]
    A --> D[sessionStorage]
    A --> E[IndexedDB]
    B --> F[Automatically attached to matching HTTP requests]
    C --> G[Client-side key value persistence]
    D --> H[Tab-scoped temporary persistence]
    E --> I[Structured offline-capable app data]
```

## Authentication in Browser Apps

Frontend interview questions about auth are often really questions about browser behavior.

### Session Cookie Model

In a traditional server-backed web app:

1. user logs in
2. server verifies credentials
3. server sends a session cookie
4. browser stores it
5. browser automatically includes it on future matching requests
6. server uses it to find the session state

```mermaid
sequenceDiagram
    participant User as User Browser
    participant App as Frontend App
    participant API as Server

    App->>API: POST /login with credentials
    API-->>User: Set-Cookie session=abc
    User->>User: Browser stores cookie
    App->>API: GET /profile
    User->>API: Cookie: session=abc
    API-->>App: profile data
```

Why this model is strong:

- browser handles cookie attachment automatically
- server can invalidate session centrally
- `HttpOnly` cookies are not readable by JavaScript, reducing exposure to token theft via XSS

### JWT Basics

JWTs, or JSON Web Tokens, are a token format often used in stateless auth systems. The token itself can carry claims and can be verified by the server.

Important nuance: JWT is a token format, not a storage strategy.

You still need to decide where to keep it:

- in memory
- in a cookie
- in storage accessible to JavaScript

That decision affects security properties more than the string format does.

### Cookie vs JavaScript-Accessible Token Storage

If you store auth material in `localStorage`, JavaScript can read it, which means XSS can read it too.

If you store auth material in `HttpOnly` cookies, JavaScript cannot read it directly, which is often safer against token exfiltration. But cookies are automatically attached to requests, so CSRF protections become especially important.

This is why authentication discussions in browser apps are always tied to both XSS and CSRF.

## XSS: Cross-Site Scripting

XSS happens when untrusted content is executed as script in your page's origin.

### Why It Is So Dangerous

The browser treats injected script as if it were your app's own JavaScript running in your origin. That means it can:

- read page data
- make authenticated requests
- manipulate the UI
- access storage available to JavaScript
- potentially exfiltrate secrets

Once XSS lands, many other defenses become weaker because the attacker is now "inside" your app's trust boundary.

### Common Causes

- injecting unsanitized HTML
- unsafe template interpolation
- dangerous use of `innerHTML`
- third-party script compromise

### Defenses

- escape or sanitize untrusted content
- prefer safe DOM APIs and framework escaping defaults
- limit inline script execution with CSP
- reduce token exposure to JavaScript when possible

## CSRF: Cross-Site Request Forgery

CSRF exploits the fact that the browser may automatically attach cookies to requests.

An attacker cannot necessarily read your app's responses because of same-origin policy, but they may still be able to cause the browser to send authenticated requests if the app relies on automatically attached credentials.

### Why CSRF Exists

The browser is trying to be convenient. If the user is logged in, the browser sends matching cookies automatically. That convenience is exactly what attackers try to abuse.

### Defenses

- `SameSite` cookie settings
- anti-CSRF tokens
- checking origin or referer where appropriate
- using auth patterns that do not blindly trust automatic cross-site requests

## CSP: Content Security Policy

CSP is a browser-enforced policy that lets a site restrict what content and scripts are allowed to execute.

Think of CSP as a damage-limiting policy layer. It does not replace safe coding, but it can greatly reduce what injected content is able to do.

Examples of what CSP can control:

- which script sources are allowed
- whether inline scripts are allowed
- which image, style, and connect destinations are allowed

This matters in real apps because modern frontends often load many third-party resources. CSP helps turn "trust everything the page references" into an explicit policy.

## Browser Security Is a System, Not a Single Feature

Strong browser security comes from layers working together:

- HTTPS protects transport integrity and confidentiality
- same-origin policy isolates sites from one another
- CORS selectively relaxes read restrictions under server control
- cookie attributes constrain credential behavior
- XSS defenses stop hostile code from entering your origin
- CSRF defenses protect automatically attached credentials
- CSP reduces the blast radius of injection mistakes

This layered thinking is what interviewers want when they ask security questions. They are usually testing whether you understand that the browser is an active security participant, not a passive request sender.

## Interview-Ready Summary

- The browser cares about origin, credentials, cache, and security policy in addition to raw HTTP semantics.
- `fetch` triggers browser-managed request logic involving policy checks, caching, networking, and async response delivery.
- Same-origin policy prevents one origin's page JavaScript from freely reading another origin's data.
- CORS is a browser-enforced mechanism that allows controlled cross-origin access when the server opts in.
- Cookies are automatically attached to matching requests; `localStorage`, `sessionStorage`, and IndexedDB are not.
- `HttpOnly` cookies reduce JavaScript access to sensitive auth material, while JavaScript-readable storage is more exposed to XSS.
- XSS, CSRF, and CSP are related browser security topics, not isolated trivia items.

## What to Read Next

Continue with [05-real-world-architecture-patterns.md](./05-real-world-architecture-patterns.md). That chapter turns all of these browser primitives into application design choices: SPA vs MPA, SSR vs hydration, state management, caching, and production frontend architecture.