Is it insecure to include your login page in your single page application? Is it insecure to include your login page in your single page application? vue.js vue.js

Is it insecure to include your login page in your single page application?


An SPA would have all the page structures (html and javascript code for the design of pages), but obviously not data. Data would be downloaded in subsequent ajax requests, and that is the point. To download actual data, a user would have to be authenticated to the server, and all security would then be implemented server-side. An unauthorized user should not be able to access data from the server. But the idea is that how pages look is not a secret, anybody can have a look at pages of the SPA without data, and that's fine.

Well, and here comes the catch that people often overlook. Html is one thing, but there is all the javascript in an SPA that can access all the data. Basically the code of the SPA is an API documentation if you like, a list of possible queries that the backend can handle. Sure, it should all be secure server-side, but that's not always the case, people make mistakes. With such a "documentation" that an SPA is, it can be much easier for an attacker to evaluate server-side security and find authorization / access-control flaws in server-side code which may enable access to data that should not be accessible to the attacker.

So in short, having access to how pages look (without data) should be ok. However, giving away how exactly the API works can in certain scenarios help an attacker, and therefore adds some risk, which is inherent to SPAs.

It must be noted though that it should not matter. As security by obscurity should not be used (ie. it should not be a secret how things work, only things like credentials should be secrets), it should be fine to let anyone know all the javascript, or the full API documentation. However, the real world is not always so idealistic. Often attackers don't know how stuff works, and it can be of real help to be able to for example analyze an SPA, because people that write the backend code do make mistakes. In other cases the API is public and documented anyway, in which case having an SPA presents no further risk.

If you put the SPA behind authentication (only authenticated users can download the SPA code), that complicates CDN access a lot, though some content delivery networks do support some level of authentication I think.

Yet there is a real benefit of having a separate (plain old html) login page outside the SPA. If you have the login page in the SPA, you can only get an access token (session id, whatever) in javascript, which means it will be accessible to javascript, and you can only store it in localStorage, or a plain non-httpOnly cookie. This may easily result in the authentication token being stolen via cross-site scripting (XSS). A more secure option is to have a separate login page, which sets the authentication token as a httpOnly cookie, inaccessible to any javascript, and as such, safe from XSS. Note though that this brings the risk of CSRF, which you wil lhave to deal with then, as opposed to the token/session id being sent as something like a request header.

In many cases, having the login in the SPA and storing the authentication token in localStorage is acceptable, but this should be an informed decision, and you should be aware of the risk (XSS, vs CSRF in the other case).


It's clear that data loaded into an SPA must be secured behind an API through authn. But I think you can also secure layout so it is "less ok" having access to how pages look. With metamodel-driven development, you can serve layout configuration from a secured API. I am not talking about serving HTML (that's SSR), I am talking about serving JSON. That layout configuration is nothing but a JSON file on the server defining the content of your screen (fully or partially). Then your SPA code turns into a generic interpreter/render of that metamodel that parses the payload, renders components and binds data. If your API is L3, voilĂ , you get a fully working API-driven app.