Ionic Role Based Authentication Routing [v4]

ionic-4-role-auth-routing

If you want to use your app for multiple user groups, chances are high you need to present different UI elements or pages to your users.

Good thing is you can easily work with different user roles inside your app and the routing since Ionic 4 to protect your pages!

There’s also a full course on user roles with Firebase inside the Ionic Academy library for all members!

ionic-4-role-based-routing

To make our app secure we can incorporate guards and some advanced logic so users can only access pages they are allowed to, and also make sure we can directly reach them if our app happens to run as a standard website!

Setting up our Ionic App

We need a bit of boilerplate code for our app so go ahead and create a new app, a few pages and also a service and guard that will contain the real logic of our app:

We also need the Ionic storage in order to save information locally once a user is logged in so we can later simply load the information and don’t require another login.

To do so, we also need to add the storage to our app/app.module.ts like this:

We don’t need any other packages in this Quick Win!

Creating a Simple Authentication Service

Let’s start with the backbone of our app, the authentication logic. Most of this is a bit fake as we don’t have a real backend in the scenario here, but you could easily plug in your own API in the right places to make a real login or to save the token you might receive then!

For us, we’ll perform a super dummy login and set the user along with a rolethat’s what we need later in our guard to allow only users with that role access to certain pages!

We also have 2 variables for:

  • authState: A Behaviour subject on which we can emit new values at anytime
  • user: The Observable that we can get from the user, and what’s used from outside

This might seem a bit strange and overkill and yes, this could work with only the Behaviour Subject like in other examples.

However, in order to achieve direct access to pages that require authentication and in order to actually route to the right page and not a standard logged in page we need this distinction. Watch the video below for more explanation on this!

Also, we use the filter() in our constructor in order to not emit the null values of our Behaviour Subject (kinda counters one of its benefits, but we still need the other functionality).

The service also takes care of calling right in the beginning so we always try to load any stored information, which normally might be a JWT for example.

Now open your services/auth.service.ts and change it to:

For the logout we just need to erase all stored data and route back to the login. As said before, we are intentionally not using a global automatic routing in app.component.ts like we did in other tutorials which isn’t as flexible as this approach!

Adding the Login/Logout

After this initially hard to consume code things get a bit easier for a while, just like a good spinning course.

The login is no magic as we just need a few fields and need to call our service function to do the login. This will return a user (actually already using the Observable flow because we make use of of()) which is as close to your API as possible, hopefully.

That means, after the login we have the role (or you should make sure you got it) so we can start our role based authentication and send the user to the appropriate page. Therefore, change your pages/login/login.page.ts to:

The view is no real magic, but of course there’s also a course on creating a more polished view inside our library.

For now, just put these few lines of code into your pages/login/login.page.html:

Besides that we also need the basic functionality to see a difference between our user and admin area. therefore, change both of these pages:

  • pages/admin-dashboard/admin-dashboard.page.html
  • pages/user-dashboard/user-dashboard.page.html

Both pages simply need a text in the header or different color and the sign out button in order to make our flow complete. This could look like:

Also, add the signOut() to both of your pages:

  • pages/admin-dashboard/admin-dashboard.page.ts
  • pages/user-dashboard/user-dashboard.page.ts

Simply import our AuthenticationService and call the functionality, the rest will be handled in there!

Ok we are almost done. By now you should be able to login, get to the user or admin page with their respective credentials and also log back out.

The problem: Even when you are logged in as the user/admin, you can access the dashboard of the other role!

To fix this problem, we need our Guard, which was also used in other tutorials on user authentication.

Implementing our Authentication Guard

The guard can protect our page and only allow users to access the page if they are authenticated – you might have seen that in other places.

Now we also want to take this one step further and check for a specific role of a user!

To do so, we can apply the guard to our pages that we want to protect inside the canActivate array but also pass the role the user needs as additional data! Of course this won’t immediately check for the role, but we get access to the routing data in our guard in the next step.

Now add the guard and data to your routing inside the app/app-routing.module.ts:

So now the guard needs to check for the authenticated user and also its role. No problem with our service!

We can use the Observable we created in the beginning in our service. Yes, we can also return an Observable inside the canActivate function!

Here we can first check for the user and second for the role and only if both checks pass, we return true which means we allow access to the route.

Go ahead with the guards/auth.guard.ts like this:

There’s a bit of RxJS logic going on, so maybe also check out the video below where I try to explain this as good as possible.

I’ve also used the parseUrl function after reading this great article on better redirects in route guards!

This piece is now also responsible for handling direct access to a page:

When the user directly calls the /user-dashboard route in the browser, our Authentication service will try to load stored user information. Then, we emit this value to our auth state and finally the auth guard receives the value – so access is allowed immediately without any further flash of other pages!

Conclusion

While it’s not as easy as some other topics, with the right approach and guards + routing you can implement even more complex authentication scenarios including user roles!

You can also find a (long) video version of this Quick Win below!