Should login page be root or route?

I have a .NetCore/Aurelia app where the client code and API services are all served from the same domain. Authentication is done against the API and uses cookie authentication as opposed to JWT/Auth Service.

Initially, I loaded app as my root and added my login page as a route.

//main.js
aurelia.start().then(() => aurelia.setRoot(PLATFORM.moduleName("app")));

//app.js
configureRouter(config, router)
{
   //...
  config.map([ {route: "/login", name: "login" ... }, ...]);

I added auth code in the navigation pipeline to check for user authentication and redirect to the login route. Once the user is authenticated, then the user is able to navigate to other routes.

One problem with my approach is that my application shell consists of a title bar across the top, a menu bar on the left and the content to the right of the menu. The <routerview> is the content area. So, when I go to the login route, I need to hide the titlebar and menu – not a big deal, but a bit of an annoyance.

I toyed with the idea of catching auth in main and setting the root based on if the user was authenticated or not. So, an unauthenticated user would have root set to login while an authenticated user would have root set to app.

//main.js
var root = PLATFORM.moduleName("login");
if(authService.isUserAuthenticated())
    root = PLATFORM.moduleName("app");

aurelia.start().then(() => aurelia.setRoot(root));

This, of course, solves the issue of having to hide menus, etc. However, I’m not sure how to switch between roots. IOW, once a user authenticates, I need to switch to app instead of login. Also, if a user is authenticated (root = app), but then admin locks the user out, the next request will come back as a 401 and the user should be redirected to login (root = login).

So, my questions are:

  1. Should login be a root or a route?
  2. If login should be a root, how do I “switch roots” when user authentication changes?
1 Like

I’ve used both approaches among others. Using multiple apps is really neat since it allows you to have a common application framework hosting the various apps that are related but isolated enough to keep apart. This is helps when it comes to bundling, being able to cleanly split between a common bundle and bundles for the various apps. My solution typically looks somewhat like this:

/src/resources/…
/src/apps/identity/…
/src/apps/identity/resources/…
/src/apps/customer/…
/src/apps/admin/…

Then in main.js, i would have the following:

async function configure(aurelia) {
   .....
  await aurelia.start();
  const app = determineApp(aurelia); // note that since we've started up aurelia, our DI container is now available
  aurelia.setRoot(app);
}

The disadvantages here are that you’ll have to do some manual routing in determineApp to decide on what app to load. and switching between apps requires extra work (easiest to just accept a page refresh). I typically use various domains as a way of routing to the correct app.

As you mentioned, the alternative is to use multiple routes. Consider using a combination of both where main.js boots up a single app, which in turn has a router routing to differing components (identity/consumer/admin/…), each being a folder with their own child router. The (dis)advantages of this method are that now each component has knowledge about the other components, e.g. the root router is shared among all.

1 Like

So I just tried to call window.location.reload(); from within a viewModel and I get an error stating that reload is not a function. How do I force a page refresh?

1 Like

That’s odd, window.location.reload is certainly a function, except when window or window.location is not available due to being in a different context (which would yield a different error)- or when somehow window got shimmed for something else, perhaps due to your build system. Do you have a repro?

What happens when you call: window.location = window.location?

1 Like

I don’t actually have a repo at this time. Setting window.location = window.location; does not thow an error in and of itself, but the call to reload() still gives the error.

I’m using WebPack as my build tool if that makes a difference.

1 Like

Forget it. I had made a change to my html and never saved the change. Sorry. The reload is actually working correctly.

2 Likes

Can you expand on that? I understand that you’d have to see if the user is already logged in, etc. – but I wouldn’t consider that routing. What kind of manual routing would have to be done here?

If you can simply call aurelia.setRoot("main-app") what extra work is required?

1 Like
  1. I think if you only have a pair of “non-authenticated” vs “authenticated” apps, your determineApp() doesn’t deal with routing, just whether a user has been authenticated. Sjaak examples have multiple apps, so I’d imagine they live under different mount points (like #/identity, #/admin, etc.). These mount points are the manual routing part.

  2. Selecting which app is easy, at least when you simply refresh the page. Dynamically routing between apps is not.

3 Likes