AngularJS: How to check auth from API using Transition Hooks of UI-Router?

Issue

How do I make the transition hook wait for the checkAuth() request from my API to fail before it would redirect the user to the login page without the transition hook successfully resolving?

This is the transition hook code I have:

app.js

angular.module('app')
  .run(function ($state, $transitions, AuthService) {
    $transitions.onBefore({ to: 'auth.**' }, function() {
      AuthService.isAuthenticated().then(function (isAuthenticated) {
        if (!isAuthenticated) {
          $state.go('login');
        }
      });
    });
  });

I’m using the $state service to redirect the user to the login page when the unauthenticated user tries to access an auth restricted view. But with this implementation, the transition onBefore() is already resolved, so the transition is succeeding before my checkAuth() method finishes. So it’s still showing the view its going to for a (split) sec, before it transitions to the login view.

Here is the implementation of the auth service methods used in the code above:

auth.service.js

authService.isAuthenticated = function () {
  // Checks if there is an authenticated user in the app state.
  var authUser = AuthUserStore.get();
  if (authUser) {
    return Promise.resolve(true);
  }
  // Do check auth API request when there's no auth user in the app state.
  return authService.checkAuth()
    .then(function () {
        return !!AuthUserStore.get();
      });
};

authService.checkAuth = function () {
  return $http.get(API.URL + 'check-auth')
    .then(function (res) {
        // Store the user session data from the API.
        AuthUserStore.set(res.data);
        return res;
      });
};

Solution

Kudos to Jonathan Dsouza for providing the HookResult documentation from UI Router.

This issue is resolved by handling the Promise from the isAuthenticated() service method, and returning the necessary HookResult value to handle the transition as required:

app.js

angular.module('app')
  .run(function ($transitions, AuthService) {
    $transitions.onBefore({to: 'auth.**'}, function (trans) {
      return AuthService.isAuthenticated().then(function (isAuthenticated) {
          if (!isAuthenticated) {
            return trans.router.stateService.target('login');
          }
          return true;
        });
    });
 });

Answered By – Ronneil Petterson

Answer Checked By – Clifford M. (AngularFixing Volunteer)

Leave a Reply

Your email address will not be published.