Building a Secure Login Pathway for SPAs With LoginRadius
Single-page apps changed how auth works. Here is how we approached SPA security at LoginRadius and the patterns worth keeping.

Single-page applications broke the assumptions every legacy authentication library was built on. There is no page refresh, no server session in the traditional sense, and no easy place to put a secure cookie. The first generation of SPA auth code stored tokens in localStorage, which turned out to be a great way to give every XSS vulnerability a path to total account takeover.
At LoginRadius we spent real engineering time on SPA auth because the modern web runs on it. Here is what worked.
The core problem
An SPA is a browser application without a backend session. You need to:
- Authenticate the user once.
- Hold an assertion of that authentication across page navigations and reloads.
- Attach proof of identity to API calls.
- Refresh the assertion before it expires.
- Revoke it on logout, idle timeout, or risk events.
Every one of those steps has a wrong way that ships in tutorials and a right way that takes more code.
What we recommend
Use Authorization Code with PKCE, not Implicit. Implicit flow returned tokens in the URL fragment, which leaked them to browser history, referrer headers, and bookmark managers. PKCE removed the need for a client secret and closed the redirect interception attack. The OAuth working group formally deprecated Implicit in 2020. If your auth library still defaults to it, replace the library.
Keep access tokens in memory. Not localStorage. Not sessionStorage. Memory. On page reload, use the refresh token to mint a new access token. This costs one round trip and removes the entire XSS-to-takeover attack class.
Store the refresh token in an HttpOnly, Secure, SameSite=Strict cookie. The browser sends it on requests to the auth server, but JavaScript cannot read it. If your architecture cannot do this (because auth and app are on different domains), use a backend-for-frontend that holds the refresh token server-side and exposes a session cookie to the SPA.
Rotate refresh tokens on every use. Single-use refresh tokens, with reuse detection that immediately revokes the chain. This catches stolen tokens within one extra request.
Short-lived access tokens. Minutes, not hours. The tradeoff for the extra refresh traffic is a much smaller blast radius if a token leaks.
CSP that actually says no. A strict Content Security Policy with nonces, no unsafe-inline, and no unsafe-eval is the single most effective defense against the XSS that would otherwise compromise everything above. Without it, the rest of this list is decorative.
What LoginRadius shipped
The platform exposed an OIDC-compliant authorization server with PKCE on by default, refresh token rotation on by default, and a JavaScript SDK that kept access tokens in memory and used a backend-for-frontend pattern when customers needed cross-domain support. Customers got the right defaults without having to know the threat model.
The principle
An SPA is hostile territory for secrets. Treat the browser as a place where any value JavaScript can read might be read by code you did not write. Design the auth flow so that the worst case (an XSS hits one of your routes) does not become a full account takeover. The patterns above are how you get there.
Get the newsletter
New writing on identity, AI security, and building software, delivered when it ships. No tracking pixels, no funnels, unsubscribe with one click.