Part II β The Shield Β· Lesson 3.5
Client-side Security
In one lineThe client is fully controlled by the user β it can enforce nothing and keep no secret.
Where you've seen itREACT_APP_API_KEY in a .env file, inlined into main.js at build time, readable by anyone who opens the Sources tab.
Diagram
WHAT THE USER CONTROLS β all of it
ββββββββββββββββββββββββββ Their machine βββββββββββββββββββββββββββ
β your JS bundle readable, editable, breakpointable β
β network requests replayable in curl, headers rewritable β
β localStorage open in DevTools β
β React state editable via extensions β
β "disabled" button removed with one DOM edit β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ every request is attacker-shaped
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β YOUR SERVER β the only place a rule is actually enforced β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββCLIENT CHECK vs SERVER CHECK β both, for different reasons
Client validation = user experience (instant feedback)
Server validation = security (the actual gate)
Hiding an admin button β tidy UI
Blocking /api/admin β the real controlTOKEN STORAGE β pick your poison
XSS-readable CSRF-prone effort
localStorage YES no low
memory (JS variable) YES no medium lost on reload
HttpOnly cookie NO YES medium SameSite fixes CSRF
Best default: HttpOnly + Secure + SameSite=Lax cookie,
short-lived access token, refresh rotated server-side.How it works
- Assume the bundle is public. Anything in it β keys, endpoints, feature flags, business logic β is disclosed.
- Keep real secrets on the server. If the browser must call a third-party API with a secret, proxy it through your backend.
- Publishable keys are fine (Stripe publishable key, Maps key) β but restrict them by referrer, origin, and scope in the provider's console.
- Re-check every authorisation on the server. Hiding UI is presentation; the endpoint is the boundary.
- Don't rely on obfuscation or minification. It slows a reader by minutes, not attackers.
Trade-offs
| Frontend can | Frontend cannot |
|---|---|
| Improve UX with fast validation | Enforce authorisation |
| Reduce blast radius (CSP, HttpOnly) | Keep a secret |
| Rate-limit gently (debounce) | Prevent request replay |
| Hide UI for unauthorised roles | Prevent access to the API |
Interview angle
"Where do you store the JWT?"
- Not
localStorageif you can avoid it: any XSS reads it instantly. - Prefer an
HttpOnly; Secure; SameSite=Laxcookie, which XSS cannot read, and handle CSRF separately. - Keep access tokens short-lived with server-side refresh rotation, so a stolen token has a small window.
Recap
- Every client-side check is a hint; every server-side check is the rule.
- Nothing shipped to the browser is secret β proxy anything that must stay private.
- Token storage is a trade between XSS exposure and CSRF exposure;
HttpOnly+SameSitehandles both.