I have a regular web app, composed as usual of a frontend SPA (angular) and a backend.
The server calls are protected from unauthorized calls through authentication provided by OpenID Connect.
My web app is accessible from the internet, and though the front by itself does not contain any user data (which is saved in a database in the backend), I still want to prevent non-users from accessing my front code, because it would leak features that I don’t want non-users to know about.
Similarly, I also want to prevent regular users from being able to see admin features (
/admin part of my website).
I know the whole point of SPA is to download everything in a single page load and then make dynamic changes, but I still want users to only download code for which they have appropriate rights (for example, you can download the 3 tabs of the main menu in one go if you have access rights for these 3 tabs, but the admin page can only be downloaded if you have admin rights).
What options do I have to make sure the user is authenticated and authorized before downloading front code, and what are their advantages / drawbacks ?
Usually in an SPA there is a single index.html file, as in this online SPA of mine. So when following a pure SPA architecture the HMTL reveals no information.
<!DOCTYPE html> <html lang='en'> <head> <meta charset='utf-8'> <meta name='viewport' content='width=device-width, initial-scale=1, shrink-to-fit=no'> <base href='/spa/' /> <title>OAuth Demo App</title> <link rel='stylesheet' href='bootstrap.min.css?t=1651226315563' integrity='sha256-YvdLHPgkqJ8DVUxjjnGVlMMJtNimJ6dYkowFFvp4kKs='> <link rel='stylesheet' href='app.css?t=1651226315563' integrity='sha256-B7pu+gcFspulW4zXfgczVtPcEuZ81tZRFYeRciEzWro='> </head> <body> <div id='root' class='container'></div> <script type='module' src='vendor.bundle.js?t=1651226315563' integrity='sha256-Rbqz3uAj5ST2WPw7vI0qTgvMYpLa5mzM85xgl96MRKI='></script> <script type='module' src='app.bundle.js?t=1651226315563' integrity='sha256-9vJJYO5Z/3lk5cbSuR+W0RW9QFA9ObGYLAXPBeL4pkY='></script> </body> </html>
If multiple HTML files are returned, this is more of a website approach, and website stacks tend to protect HTML files using cookies to prevent any disclosure.
- /unsecured/app-unauthenticated.bundle.js - /secured/app-area1.bundle.js - /secured/app-area2.bundle.js
You would need to look into code splitting and lazy loading. In your app you can control when dynamic inports occur, so your code would never request secured bundles when the user is unauthenticated.
If you are concerned about a hacker accessing your JS bundles outside of your own code, as for my bundle above, then you
could secure access to bundle files by checking for cookies, or even going so far as checking claims in underlying OAuth access tokens, though I would not do any of this.
My web host is the AWS Cloudfront Content Delivery Network (CDN), where Lambda Edge Extensions can run code before assets are served. Currently the only role of my lambda edge code is to serve a default document and issue recommended web security headers.
This code could be updated to make the same cookie checks as API gateway code, eg to return a 401 JSON response if it a valid cookie was not supplied. It would add considerable complexity though, and it is more standard to ensure at design time that UI code does not need securing.
Answered By – Gary Archer
Answer Checked By – Mildred Charles (AngularFixing Admin)