Search code examples
angularangular-routeroktaangular-router-guardsokta-signin-widget

Angular - Is it possible to take the inversion of the result of a router guard?


I am writing an Angular application using Okta for authentication. I have some pages that I only want to allow a user to activate if they are not authenticated. I could not find any guards or functions in the version of the Okta package I am using, but it does have a router guard (OktaAuthGuard) to check if a user is authenticated. Is it possible to use the opposite result of this guard, or create a guard which takes the inverse of the canActivate() function of OktaAuthGuard, to get my desired functionality?

Package versions:

@okta/okta-angular: 2.2.1

@okta/okta-signin-widget: 5.16.1


Solution

  • This is not possible, as the router guard may or may not run other conditional code before returning a true or false value from the Guard's CanActivate() function. In the case of the packages you mentioned, the Okta router guard will redirect to the login widget page (or start an alternative login flow) before returning false.

    A solution to this problem requires knowledge of the logic used by that route guard. A new route guard using the inverse logic of the original (ie. returning true instead of false and vice versa) must be implemented.

    In the case of the guard in the question, viewing the source code[1] show that it uses the following logic in the CanActivate fucntion:

    // Track states for current route
    this.state = state;
    this.onAuthRequired = route.data && route.data.onAuthRequired || this.onAuthRequired;
    
    // Protect the route after accessing
    this.oktaAuth.authStateManager.subscribe(this.updateAuthStateListener);
    const isAuthenticated = await this.oktaAuth.isAuthenticated();
    if (isAuthenticated) {
      return true;
    }
    
    await this.handleLogin(state.url);
    
    return false;
    

    This code uses a function to check if a user is authenticated, and thus able to activate the guarded route. An example route guard that inverts this logic would look like the below code snippet. You can add your own redirects or other handling for either case as needed:

    import ...
    
    export class NotAuthenticatedGuard implements CanActivate {
    
      authProvider:
    
      constructor(private router: Router,
                  private oktaAuthService: OktaAuthService,
                  private route: ActivatedRoute)
      {
    
        this.authProvider = oktaAuth;
    
      }
    
      async canActivate(
        route: ActivatedRouteSnapshot,
        state: RouterStateSnapshot): Promise<boolean>
      {
    
        if (await this.authProvider.isAuthenticated())
        {
    
          // Add handling here
          return false;
    
        }
    
        // Add handling here
        return true;
    
      }
    }
    

    Sources: [1]: https://github.com/okta/okta-angular/blob/master/lib/src/okta/okta.guard.ts