Arthur Daniel Arthur Daniel - 2 months ago 6
Dart Question

Securing Routes In Dart Webapp

I am building a Dart/Aqueduct webapp in which I need to be able to restrict access to certain routes. I am making use of Aqueducts Authorizers for when an HTTP request is made, but I am a little concerned about controlling user access within the dart app itself.

When routing to different pages within the webapp I use Dart routing, ie:

const Route(path: '/heroes', name: 'Heroes', component: HeroesComponent)


This allows me to use a different template and component at a new URL, however there is no HTTP request made. Is there a way to effectively implement user scopes once the user is within the app?

I was thinking of checking the access token on the routed components initialization, and not displaying the information if the user is not authenticated, but wouldn't the user still have access to that page contents since dart webapps come in a precompiled JS package?

Answer Source

Forgive me if I misunderstood your question or if you know most of this already, but it sounds like you're asking about the distinction between data being displayed by an application and the application itself. Or more generally, the difference between a single page application and a server-side rendered page.

In a server-side rendering application, every navigation loads a new URL from the server (or cache). The server uses authorization information from the request to fetch the appropriate data, insert it into a templated HTML page and then returns that page. According to the client, the data the page displays and the page itself are a single entity. If the data can't be fetched, a different page is returned indicating that the user doesn't have access.

In a single page application, every possible 'page' you can navigate to is downloaded once and they are all devoid of any actual data. Instead, these pages are a container for data. The behavior of these pages make API requests to the server for the data to display.

The application itself isn't protected - anyone can navigate to it or any of its pages. However, the data is protected. If the user doesn't have access to the data requested by an API call, a 401 status code is returned with JSON error body.

Therefore, there has to be a distinction between the client and server-side routes. You have already noticed that client-side routes don't actually make an HTTP request - this is intentional.

If you are serving the application and the API from the same application, it is a good idea to prefix all of your API routes with something like /api. For example, the client-side route is /heroes and the server-side route is /api/heroes. This also allows a mobile application (or any other non-browser application) to consume your API; they won't want the HTML because they have their own rendering behavior.

As G√ľnter said, if there a page that is useless without access to the API data, punt them back to a login page. There are two scenarios where you don't have access to API data: you don't have an access token at all and your access token is expired.

Make the API request when you navigate to the /heroes client-side route. If you don't have an access token, punt them to a login page. If the request yields a 401, punt them back to a login page. If you get back 200, then operate as normal.

One place where client-side routing gets in the way is when trying to type a client-side route URL into a browser (as opposed to programmatically navigating to it). There are different strategies to side-step this, here's one: https://github.com/stablekernel/aqueduct/issues/274.