Frontend Architecture

[Frontend Architecture] Auth - F12-Premised Browser Security Architecture

[Frontend Architecture] Auth - F12-Premised Browser Security Architecture

About this article

As the seventh installment of the “Frontend Architecture” category in the series “Architecture Crash Course for the Generative-AI Era,” this article explains frontend-side authentication and authorization.

The frontend runs in the user’s hands - and the attacker’s hands. We treat browser-specific defenses on the premise that F12 can peek into and rewrite every variable. This article covers XSS/CSRF defenses, Cookie attributes, CSP, token storage locations, and refresh strategies, while leaving authentication methods (MFA, Passkey, IDaaS selection) to the security chapter and session implementation to the software chapter.

What is frontend auth design in the first place

Frontend auth design is, roughly speaking, “deciding how to safely handle user credentials inside the browser — an environment in the enemy’s hands.”

Imagine a glass safe. The contents are fully visible and the keyhole is exposed — that’s the browser environment. Opening F12 (DevTools) lets you peek at every variable and Cookie. Designing “where to store tokens” and “how to build a mechanism that can’t be stolen via XSS” under this premise is frontend auth design.

Why frontend auth design is needed

The browser runs “in the enemy’s hands”

Server-side code is accessible only to administrators, but browser JavaScript is fully visible and modifiable via F12. A design that ignores this premise renders all authentication meaningless.

Wrong token-storage choice becomes instant vulnerability

Put JWT in localStorage and it’s stolen by XSS; mis-set Cookie attributes and it’s exploited by CSRF — the choice of storage location and attributes directly determines the security level.

Must align with server-side auth design

Authentication doesn’t complete on the frontend alone. Without designing it as a pair with the backend’s auth and session design, one side’s defenses become meaningless.

This article’s coverage

ArticleCoverage
This article (frontend auth)F12-premised authorization UI / Cookie attributes / XSS / CSRF / CSP / token storage
50/01 Auth designAuth strength / MFA / Passkey / IDaaS / SSO strategy
50/02 Authorization and IAMDesign of RBAC / ABAC / ReBAC
20/07 Authentication and sessionsServer session vs JWT / OAuth implementation

This article does not cover “MFA factor selection,” “IDaaS selection,” or “authorization model details.” What the frontend should do is decide what to defend in the hostile territory called the browser.

The question of this article is “what can you do on the premise that F12 can rewrite anything?” Authentication methods themselves are handled in another chapter.

The frontend is “an ultimately untrusted environment”

Frontend authorization checks are just UI decoration. UX control like showing/hiding the admin button is fine in the frontend, but real security checks must always happen on the server side. The moment you bend this principle, auth design collapses.

I had an experience as a junior - thinking my design that checked role === 'admin' only on the frontend was “fine because it doesn’t show the admin screen” - shattered in one shot by a senior saying “open F12 and you can see everything.” Hitting the limits of frontend authorization usually happens after taking this kind of hit.

Frontend authorization is just for UI conditional rendering. The real lock goes on the server - that’s the rule.

Four authentication choices

From the frontend’s perspective, there are essentially only 4 patterns. “SPA so JWT” is an old 2010s indoctrination - the modern standard is Cookie + BFF.

MethodDetail
Server session (Cookie)Same-domain standard, simplest
JWT in localStorageLandmine - one XSS leaks everyone’s tokens
JWT in httpOnly CookieHybrid, the realistic top choice
OAuth/OIDC delegationExternal platforms like Auth0 / Cognito / Firebase Auth

“SPA so put JWT in localStorage” is a trap still mass-produced by old sources. If even one XSS gets through, all users’ tokens are taken. Even when using JWTs, put them in “httpOnly Cookie.” Raw localStorage operation is synonymous with accidents.

“SPA = JWT in localStorage” is a finished design. Cookie + BFF is the modern first choice.

Login flow (Authorization Code + PKCE)

Authorization Code + PKCE is the standard login flow for modern SPAs. Third-party auth from Google, Apple, GitHub, etc. all adopt the same shape. PKCE (Proof Key for Code Exchange, an extra check to prevent code interception) is an additional verification step to crush “code-interception attacks” on public clients.

1. User → redirect to auth server (with code_challenge)
2. After login, code is returned
3. Get tokens with code + PKCE verifier
4. BFF verifies and issues a Session Cookie
5. Subsequent API calls use the Cookie

PKCE’s idea is simple: the client makes a random verifier and passes its hash (challenge) on the first request. Later, when exchanging the code for tokens, the original verifier must be presented. Even if the code is stolen mid-flight, an attacker without the verifier can’t use it. Required for public clients like mobile and SPAs.

Authorization Code with PKCE - the only choice. Never use the old Implicit Flow.

For Cookie-based auth, attribute settings literally decide security. They look mundane, but missing one creates a critical XSS-Cookie-leak vulnerability.

AttributeMeaning
HttpOnlyCannot be read from JS (most important XSS countermeasure)
SecureSent only over HTTPS
SameSite=LaxDefault safe value, CSRF countermeasure
SameSite=StrictFull CSRF prevention (UX impact)
DomainSpecified when sharing across subdomains
PathLimits the path it applies to

The modern minimum line is the triad of HttpOnly + Secure + SameSite=Lax. This single set blocks Cookie reading via XSS, eavesdropping over HTTP, and accidental cross-site sending.

Forgetting one attribute and it’s over. Putting it on a checklist and checking mechanically is the rule.

XSS and CSRF

The two big threats facing the frontend are XSS and CSRF. They’re different things, but each collapses an auth system in one shot. Always design countermeasures as a set.

flowchart TB
    XSS["XSS<br/>Cross-Site Scripting<br/>malicious JS runs on the page"]
    CSRF["CSRF<br/>Cross-Site Request Forgery<br/>authenticated request fired from another site"]
    XSS_M1[CSP<br/>narrow allowed sources via script-src]
    XSS_M2[Escaping<br/>leave to template engine]
    XSS_M3[HttpOnly Cookie<br/>unreadable from JS]
    CSRF_M1[SameSite Cookie<br/>Lax/Strict]
    CSRF_M2[CSRF token<br/>required for POST requests]
    XSS --> XSS_M1
    XSS --> XSS_M2
    XSS --> XSS_M3
    CSRF --> CSRF_M1
    CSRF --> CSRF_M2
    XSS -.|if XSS gets through<br/>other defenses are nullified|.-> CSRF
    classDef threat fill:#fee2e2,stroke:#dc2626,stroke-width:2px;
    classDef defense fill:#dbeafe,stroke:#2563eb;
    class XSS,CSRF threat;
    class XSS_M1,XSS_M2,XSS_M3,CSRF_M1,CSRF_M2 defense;
AttackContentCountermeasure
XSS (Cross-Site Scripting)Inject malicious JS into the pageCSP / escaping / HttpOnly Cookie
CSRF (Cross-Site Request Forgery)Fire authenticated requests from another siteSameSite Cookie / CSRF token

The moment XSS gets through, auth is effectively void. Once attackers can run JS, all info except Cookies is taken, and APIs can be hit while impersonating the user. So frontend security goes XSS countermeasures first, CSRF second - in that order.

The moment XSS is allowed, you’ve lost. Other countermeasures collapse from a broken premise.

CSP (Content Security Policy)

CSP (Content Security Policy, an HTTP header that declares allowed resource sources to the browser) is a mechanism for declaring to the browser “the allowed sources of scripts, styles, and images on this page.” It’s the trump card of XSS countermeasures - just the setting “no inline scripts” neutralizes most XSS attacks.

Content-Security-Policy:
  default-src 'self';
  script-src 'self' https://trusted.cdn.com;
  style-src 'self' 'unsafe-inline';
  object-src 'none';

Banning inline scripts is a powerful move that wholesale invalidates injections like <script>alert('xss')</script>, but applying it suddenly to existing pages breaks the site - so phase it in. Next.js and Astro auto-inject CSP nonces, so the entry barrier dropped a lot from the modern-FW side.

CSP is the heart of XSS countermeasures. With a modern FW there’s no reason not to introduce it.

Authorization UI in the frontend

Authorization in the frontend centers on UI conditional rendering like “show/hide admin button.” This is a UX matter, not security - hiding the screen and actual permission control are different things.

{user.role === 'admin' && <AdminPanel />}

This stops the admin features from rendering, but an attacker can rewrite the condition to true in F12 and display AdminPanel. At that point, the admin API must not be callable - so permission checks must always exist on the API side.

Design principles:

  • Data returned by APIs is permission-filtered
  • Page-transition guards (router middleware) are auxiliary
  • Don’t even fetch info you don’t want shown

Authorization model design (RBAC / ABAC / ReBAC) is consolidated in the security chapter because it isn’t frontend-specific. What the frontend side of this article should grasp is the principle: “no matter which authorization model you adopt, doing the permission check on the frontend collapses the design.”

Frontend authorization is UX decoration. Real security always sits on the server.

Token storage

Where you place auth tokens makes a vast difference in security level. The modern standard is httpOnly Cookie as the base, used together with memory.

LocationSafetyNotes
httpOnly CookieExcellentUnreadable from JS, doesn’t leak via XSS
Memory (Redux / variables)GoodDisappears on reload
sessionStorageMarginalCleared on tab close, but XSS-vulnerable
localStorageBadAvoid - one XSS leaks everyone’s tokens

The recommended composition is “short-lived Access Token in memory, long-lived Refresh Token in httpOnly Cookie.” The memory side auto-clears on reload; the Cookie side is shielded by httpOnly - a two-layer defense stands up.

Refresh token strategy

Splitting Access Token and Refresh Token is the modern standard pattern for session management. Hit daily APIs with the short-lived Access Token, and refresh with the long-lived Refresh Token when it expires.

1. Access Token (15 min) expires
2. Client sends Refresh Token (30 days, Cookie)
3. BFF issues a new Access Token
4. Optionally rotate the Refresh Token (re-issue)

Refresh Token Rotation is a mechanism that issues a new Refresh Token each time it’s used, immediately invalidating the old one. If the old token is reused, it’s detected as stolen and the entire session is revoked. Auth0 and Firebase Auth support this natively, and adding it raises safety one rank.

Refresh Token Rotation + httpOnly Cookie is the modern recommended composition.

Logout and revocation

Logout tends to be taken lightly, but it’s quietly central to security. Just “delete Cookie when button clicked” isn’t enough - the server must also revoke the Refresh Token.

ItemDesign
LogoutDelete Cookie + revoke Refresh Token on server
All-device logoutDiscard all of the user’s Refresh Tokens
After password changeAll sessions auto-revoke
On suspicious-behavior detectionAdmin can force-revoke

“All-device logout” is for emergency stops in case of theft or loss, and is required for high-importance services. The accident “logged out but old tab still works” is a direct line to incident.

Author’s note - cases where “looking-defended-only” collapsed

In 2022, it was reported that Slack had some employee tokens stored on GitHub stolen, and through those tokens, parts of internal private repos were accessed. The mechanism itself was “general token-based auth,” and the code worked correctly. Even so, it was breached due to laxness in storage location and revocation operations - a story still talked about today.

In the same 2022, there was also the report that a Sitel device entrusted with Okta support work was breached, and the LAPSUS$ group reached the level of taking screenshots of Okta’s internal screens. The very source of SSO - the auth platform - was shaken via a contractor’s terminal.

I’ve seen with my own eyes in past projects the structure where “the code is perfect, but breached through operational gaps,” and from then on I’ve thought of these stories as not someone else’s problem. All of them happen in situations where “the frontend code is clean” and “the protocols are standard.” Authentication is something defended by both wheels of code-correctness and operational-correctness; cases that drove home, even from the outside, the fact that one wheel alone leaves holes.

Authentication is both wheels of code and operations. With one alone, holes always remain.

Note: Industry baseline values as of April 2026. Will become outdated as technology and the talent market shift, so requires periodic updates.

Leaving the “correct defaults” vague in frontend auth always opens holes. Below are the modern Web standard values.

SettingRecommendedReason
Access Token expiry15 minutesMinimize damage on leak
Refresh Token expiry14-30 daysBalance with UX
Refresh Token RotationEnableDetects theft, revokes all sessions
Cookie HttpOnlyRequiredCannot be read by XSS
Cookie SecureRequiredHTTPS-only
Cookie SameSiteLax (minimum) or StrictCSRF countermeasure
CSP script-src’self’ + nonceInline forbidden
Lighthouse Best Practices100Comprehensive security basics
Auth-failure rate limit5 attempts / 15 minBrute-force countermeasure
Passkey supportRequired to consider from 2026Standard SMS-MFA replacement

“HttpOnly / Secure / SameSite=Lax” as a triad is the minimum line for Cookies. Missing even one is out of the question - it’s a basic check verifiable instantly in Chrome DevTools.

Forgetting one attribute and it’s over. Verify mechanically with a checklist.

Frontend auth pitfalls and forbidden moves

Here are the typical accidents in frontend auth. All of them are direct causes of all-user leaks, impersonation, and session hijacking.

Forbidden moveWhy it’s bad
Store JWT in localStorageLandmine - one XSS leaks everyone’s tokens. The trap of old 2010s sources
Branch only on user.role === 'admin' in the frontendF12 can rewrite to true. Server-side authorization is required
Newly implement OAuth Implicit FlowDeprecated from 2020 onward. Authorization Code with PKCE is required
Without PKCE for Authorization CodeOn public clients, code interception finishes you
Forget HttpOnlyCookies become readable by XSS. An attribute miss is an instant accident
SameSite as None without SecureCSRF passes through. SameSite=Lax is the default safe value
Leave unsafe-inline in CSPCSP introduction is meaningless. Doesn’t function as XSS countermeasure
Logout that only deletes the CookieServer-side Refresh Token survives. Revocation API is required
Password reset with predictable tokensBrute-forceable. 128-bit entropy + 15-min TTL
Rely on SMS MFA onlyBroken by SIM-swap fraud. TOTP / Passkey required
Self-implement authBecomes hole-ridden. Delegate to Clerk / Auth.js / Auth0
Skipping CSP as “it’s for big sites, not mine”Next.js/Astro have auto nonce-injection. Abandoning the XSS-countermeasure baseline
Not enabling Refresh Token RotationTheft detection doesn’t work; can’t revoke all sessions on leak

The 2022 Okta breach (366 customers affected via Lapsus$), the 2022 LastPass leak (encrypted vault copies leaked), the 2023 Cloudflare-via-Okta intrusion — the reality that even security specialists are breached. Monitoring “the delegation target’s MFA, audit logs, and least privilege” on the operational side is essential.

For authentication: don’t write it, borrow it, and watch it. Never miss one of the three.

AI decision axes

Favored in the AI eraDisfavored in the AI era
External delegation like Clerk / Auth.js / NextAuthSelf-implemented Cookie sessions
Standard protocols like Passkey / OIDCCustom auth-token designs
httpOnly Cookie via BFF operationsStoring JWT in localStorage
Explicit CSP, HttpOnly, etc. in codeSettings left to defaults
  1. Delegate to external auth platforms (Clerk / Auth.js / Auth0 / Firebase Auth)
  2. httpOnly Cookie + BFF as base composition (localStorage forbidden)
  3. Authorization always on the server side (frontend only does UI conditional rendering)
  4. Passkey + OIDC standard protocols (avoid custom designs)

What to decide - what is your project’s answer?

For each of the following, try to articulate your project’s answer in 1-2 sentences. Starting work with these vague always invites later questions like “why did we decide this again?”

  • Auth method (Cookie / JWT / external delegation)
  • Auth platform (self-built / Auth0 / Cognito / Firebase Auth / Clerk)
  • Cookie attribute settings (HttpOnly / Secure / SameSite)
  • Mandatory MFA (admins only / all users)
  • Timing of Passkey support
  • SSO support (SAML / OIDC)
  • Authorization model (RBAC / ABAC / ReBAC)
  • Session timeout and refresh strategy

Summary

This article covered frontend auth, including browser-premised XSS/CSRF defenses, Cookie attributes, CSP, token storage, Refresh Token Rotation, and external-platform delegation.

Identify what’s defendable on the F12 premise, place httpOnly Cookie + BFF as the base, and delegate authentication to external platforms. That is the practical answer for frontend auth in 2026.

Next time we’ll cover SEO (search engine optimization, OGP, sitemap, structured data).

Back to series TOC -> ‘Architecture Crash Course for the Generative-AI Era’: How to Read This Book

I hope you’ll read the next article as well.