Cheat sheet · The Browser Contract: Auth, Storage, Security & HTTP

The Browser Contract cheat sheet

What the browser does between Enter and a usable page, and the rules you need in an interview: storage, auth, CORS, caching, HTTP codes, security and speed. Always break time down by layer and use numbers.

Read the full series →

blogs · jp-blogs.vercel.app/cheatsheets/series/browser

Enter to pixels: 11 stepsLesson 0 →

  1. Input: URL or search? Normalise it (add scheme, lowercase host).
  2. Shortcuts: HSTS, Service Worker, HTTP cache, bfcache.
  3. DNS: browser, OS, resolver, then root, TLD, authoritative.
  4. TCP handshake (1 RTT) or QUIC for HTTP/3.
  5. TLS 1.3: 1 RTT, certificate checked.
  6. Request with cookies, then server work (CDN, app, DB). Time to first byte is TTFB.
  7. Parse HTML to DOM and CSS to CSSOM. Style, layout, paint, composite.
  8. After load: hydration, lazy resources, API calls. Painted is not interactive.

Tip: Cold HTTPS over TCP is DNS + 1 RTT + 1 RTT before the first request byte. At 250 ms RTT that is 500 ms or more.

What skips workLesson 0 →

CacheSkips
bfcacheEverything (whole page from memory)
Service WorkerThe network
HTTP cache, freshDNS, TCP, TLS, request, server
HTTP cache, 304Only the body download
Connection reuse (H2/H3)TCP and TLS handshakes
CDN / RedisOrigin work / database work
Script tagBlocks parsing?Order kept?
Plain scriptYesYes
asyncOnly while runningNo
defer / type=moduleNo (runs after parse)Yes
  • dns-prefetch looks up, preconnect opens DNS+TCP+TLS, preload fetches one file.
  • CSS blocks rendering. Plain JS blocks parsing. HTTP/3 removes TCP head-of-line blocking.

Five browser storesLesson 1 →

StoreLivesSizeSent to server?
CookieUntil Max-Age/Expires~4 KB eachYes, every request
localStorageUntil cleared~5 MBNo
sessionStorageUntil the tab closes~5 MBNo
IndexedDBUntil clearedLarge, asyncNo
Cache APIUntil evictedLarge, asyncNo
  • localStorage: sync, strings only, shared by every script on the origin, storage event in other tabs.
  • Storage can vanish (Safari ~7 days idle, low space). Wrap calls in try/catch. Keep the real copy on the server.
  • Secrets go nowhere in the browser. Theme the server needs: cookie. Big or binary data: IndexedDB.

Cookie attributesLesson 1 →

HttpOnly
JS cannot read it (stops theft, not use)
Secure
Send over HTTPS only
SameSite
Lax, Strict or None. None needs Secure. Set it yourself
Domain
Omit = exact host. Set = all subdomains (riskier)
Path
Convenience only, not a security wall
__Host- prefix
Forces Secure, Path=/, no Domain
Partitioned
Third-party cookie kept per top-level site
Set-Cookie: __Host-sid=abc; Path=/; Secure;
  HttpOnly; SameSite=Lax; Max-Age=3600

A good session cookie.

Session vs JWT and claimsLesson 2 →

AspectServer sessionJWT
Data livesServer (Redis/DB)In the token
Per requestStore lookupSignature check, no I/O
Logout / revokeEasy: delete recordHard until exp
Role changeNext requestAfter expiry or refresh
Best forFirst-party web appsAPIs, mobile, many services
iss / aud
Issuer you expect / token is for your API
sub
The user
exp / nbf / iat
Expiry / not before / issued at (Unix seconds)
jti
Token ID, for a deny list
  • Pin algorithms when verifying. Defeats alg: none and RS256-to-HS256 confusion.
  • decode only reads. verify checks signature and claims. Treat kid as untrusted input.
  • HS256 = one shared secret (verifier can forge). RS256/ES256 = private signs, public verifies (JWKS).
  • Access token 5 to 15 min. Refresh token in HttpOnly cookie, recorded on the server, rotated on each use.
  • Reused old refresh token means theft: revoke the whole family. "Log out everywhere": bump tokenVersion.

Watch out: A signed JWT (JWS) is not encrypted. Anyone can base64-decode the payload. Never put secrets in it.

XSS vs CSRF and token homesLesson 3 →

WhereXSS steals it?CSRF?
localStorage tokenYesNo
Non-HttpOnly cookieYesYes
HttpOnly cookieNo, but XSS can still use itYes, defend
JS memoryHarderNo
  • Strong defaults: HttpOnly session cookie; access token in memory + HttpOnly refresh cookie; or a BFF (no tokens in the browser).
  • CSRF layers: SameSite, CSRF token, Origin check, Sec-Fetch-Site, custom header, never change data on GET.
  • Lax fails against sibling subdomains (same site, different origin). JWT in a cookie still needs CSRF defence.

CORSLesson 4 →

  • Origin = scheme + host + port. CORS lets a server allow other origins to read responses. It is browser-only.
  • Simple request: GET/HEAD/POST with form-type Content-Type. JSON, Authorization or PUT/DELETE trigger an OPTIONS preflight.
  • With credentials: credentials: "include", exact origin (no *), Allow-Credentials: true, Vary: Origin.
Allow-Origin: https://app.example.com
Allow-Methods: GET, POST, PUT
Allow-Headers: content-type, authorization
Allow-Credentials: true
Max-Age: 600
Vary: Origin

Preflight reply (204). Each name starts with Access-Control-.

Watch out: CORS is not API security and not CSRF protection. Put CORS middleware before auth, or the preflight gets 401. A 5xx without headers shows as a CORS error.

Cache-Control directivesLesson 5 →

max-age=N
Fresh for N seconds, no request
s-maxage=N
Shared caches only, overrides max-age
no-cache
Store, but revalidate before each use
no-store
Never store (sensitive data)
private / public
Browser only / any cache
immutable
Never changes at this URL
stale-while-revalidate=N
Serve old copy while refreshing
ETag / If-None-Match
Validator. Unchanged gives 304, no body

Watch out: 304 saves the download but still costs a round trip. No Cache-Control means guessed (heuristic) freshness.

Caching recipe and stale deploysLesson 5 →

ResourceHeader
Hashed JS/CSS, /_next/staticpublic, max-age=31536000, immutable
HTMLno-cache
Public API datapublic, s-maxage=60, stale-while-revalidate=300
Per-user dataprivate, no-cache or no-store
  • Stale after deploy? Check HTML max-age, CDN copy (Age, x-cache), unhashed names, deleted old chunks, Service Worker, API caching.
  • Cache-bust by changing the URL (content hash). Send Vary for Accept-Encoding, Origin.

Methods and status codesLesson 6 →

MethodSafeIdempotent
GET / HEAD / OPTIONSYesYes
PUT / DELETENoYes
POSTNoNo (use an idempotency key)
PATCHNoDepends on the patch
401
Not logged in (send WWW-Authenticate)
403
Logged in, not allowed
409 / 412
State conflict / If-Match failed
422 / 400
Valid format, bad meaning / broken request
429
Rate limited, send Retry-After
202
Accepted, work queued
502 / 503 / 504
Bad upstream / overloaded / upstream timeout

RedirectsLesson 6 →

CodePermanent?Method kept?
301Yes (cached)May become GET
302NoMay become GET
303NoAlways GET
307NoKept
308Yes (cached)Kept

Tip: After a form POST use 303 (Post/Redirect/Get). Moved POST API: 307 or 308. Unsure it is permanent: use 302/307.

Frontend security and headersLesson 7 →

  • React escapes {value}. Sinks: dangerouslySetInnerHTML, innerHTML, eval, javascript: in href, postMessage without event.origin.
  • Sanitise HTML with an allow-list (DOMPurify). Allow only http:/https: URLs.
  • Authorization lives on the server. Hiding a button is not security.
  • Supply chain: lockfile + npm ci, audit in CI, few deps, no install scripts, SRI on third-party files.
Strict-Transport-Security
HTTPS only for a set time (HSTS)
X-Content-Type-Options: nosniff
No MIME guessing
Referrer-Policy
strict-origin-when-cross-origin
Permissions-Policy
Switch off camera, mic, geolocation
frame-ancestors / X-Frame-Options
Stops clickjacking
COOP / COEP
Isolate the page (SharedArrayBuffer)
Content-Security-Policy: default-src 'self';
  script-src 'nonce-R4ND0M'
    'strict-dynamic';
  object-src 'none'; base-uri 'none';
  frame-ancestors 'none'

Start with Content-Security-Policy-Report-Only.

Rendering and the event loopLesson 8 →

  • One main thread runs JS and rendering. Frame budget 16.7 ms (60 Hz). Long task: over 50 ms.
  • Loop: one task, then all microtasks, then rAF callbacks, then style, layout, paint.
  • Animate transform and opacity (composite only), not top, width, height (layout).
  • Layout thrashing: read (offsetHeight), write, read... Batch reads first, then writes, in rAF.
  • Use { passive: true }, IntersectionObserver, scheduler.yield(), Web Workers, content-visibility: auto.

Tip: Order: sync code, promise/microtask, timeout. A long microtask chain starves rendering. Debug in the Performance panel with 4x CPU throttle.

Core Web VitalsLesson 9 →

MetricGoodPoor
LCP (loading)≤ 2.5 s> 4 s
INP (response)≤ 200 ms> 500 ms
CLS (stability)≤ 0.1> 0.25
  • Judged at the 75th percentile of real users, mobile and desktop apart.
  • LCP = TTFB + load delay + load duration + render delay. Hero: img tag, fetchpriority="high", srcset, never lazy.
  • INP = input delay + processing + presentation. CLS fix: set width/height or aspect-ratio, reserve ad slots.
  • Field data (CrUX, web-vitals) says what users feel. Lab (Lighthouse) reproduces. INP replaced FID in March 2024.

Interview one-linersLesson 0 →

QuestionShort answer
no-cache vs no-store?Revalidate before use vs never store.
Does HttpOnly stop XSS?No. It stops cookie theft, not use of the session.
Is CORS a firewall?No. Browser-only; it blocks reading the response, not the request.
401 vs 403?Not logged in vs logged in but not allowed.
JWT logout?Drop client token, revoke refresh token, short exp, deny list or version.
Why INP over FID?It covers all interactions and the full delay.
Why does the Postman call work?Postman does not enforce CORS.

A cheat sheet is a reminder, not a teacher. Each card links to the lesson that explains it step by step.