Home > Enterprise >  Web App SPA & OIDC: How to properly authenticate before accessing the front?
Web App SPA & OIDC: How to properly authenticate before accessing the front?

Time:05-15

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 ?

CodePudding user response:

You could use the CanLoad guard to check user permissions.

This guard will not only determine if users can navigate to a given route, it will also prevent the download of the module code when not authorized.

CodePudding user response:

HMTL

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.

JAVASCRIPT

Javascript has traditionally not been secured in either SPAs or website tech stacks, since you need to allow Javascript to download in order to render an initial page, eg with a login button.

My deployed Javascript application code is not secured and is available in this bundle file. It is minified, so also does not reveal much. Of course, there should be nothing really secret in UI logic, and APIs should be making all security decisions for the SPA.

My SPA could use a package such as Javascript Obfuscator to further hide Javascript logic. The reason I have not done this is that exception stack trace lookup from source maps no longer works, but I would use obfuscation if I could find a solution where this was supported.

MULTIPLE JAVASCRIPT RESOURCES

If you need to secure Javascript you will need to build the SPA into multiple bundles such as these. Some website stacks provide this type of option, by hosting secured assets in a different folder. The web backend then checks that requests for those assets have an auth cookie:

- /unsecured/app-unauthenticated.bundle.js
- /secured/app-area1.bundle.js
- /secured/app-area2.bundle.js

For SPAs the same type of code can be written in a web host. My demo SPA is deployed to the AWS Cloudfront Content Delivery Network (CDN) and I could write Lambda Edge Extensions to make cookie based checks when serving Javascript files. This would be awkward though, and add complexity, so I would not use this approach unless you have special reasons.

SUMMARY

Here are some up to date Javascript recommendations, and I would maybe aim to do what it says in item 9, since it is hopefully fairly easy to implement.

Out of interest my Demo SPA implements OpenID Connect using the Token Handler Pattern. This is focused on a design that separates web and API concerns so that you do not need to deal with security as part of your web hosting.

  • Related