← Back to list

Execute Angular Guards Sequentially and in Order

TL;DR

Anass Guendef · 2025-12-02 10:06 · 4 claps · 1.9 min read
#angular #angular-guards #security
Open on Medium ↗
Wiki topics: 🌐 · Web Development

Execute Angular Guards Sequentially and in Order

TL;DR

By default, Angular runs all guards for a route in parallel, stopping at the first blocking result. This utility wraps that behavior to force sequential execution in the order you define: continue as long as each guard returns true, and stop immediately if a guard returns false or an UrlTree (redirect).


canActivate: [
  OrderedAsyncGuardUtils.orderedAsyncGuards([AuthGuard, RoleGuard, BusinessGuard])
]

The Problem

In complex apps, you often need to control the execution order of guards to:

  • Ensure prerequisites (e.g., authentication before role checks),
  • Avoid unnecessary calls (don’t hit APIs if a previous guard already blocks),
  • Make navigation logic predictable and readable.

Angular runs guards in parallel by default. Even though it stops at the first blocking result, the order is not guaranteed, and multiple guards may run simultaneously.

The Solution

OrderedAsyncGuardUtils lets you:

  • Instantiate guards via Angular DI (inject(...)),
  • Normalize return types (boolean | UrlTree | Promise | Observable) into Observable<boolean | UrlTree>,
  • Chain them sequentially using RxJS (concatMap),
  • Stop immediately on false or UrlTree,
  • Return the last emitted value (true, false, or UrlTree).

API Overview

Guard Interface


export interface OrderedGuard {
  canActivate(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): boolean | UrlTree | Observable<boolean | UrlTree> | Promise<boolean | UrlTree>;
}

Guard Class Type

export type GuardClass = { new (...args: any[]): OrderedGuard };

Utility Method

OrderedAsyncGuardUtils.orderedAsyncGuards(guards: GuardClass[]): CanActivateFn;

Example Usage

1) Three simple guards


@Injectable({ providedIn: 'root' })
export class AuthGuard implements OrderedGuard {
  constructor(private auth: AuthService) {}
  canActivate(): boolean | UrlTree {
    return this.auth.isLoggedIn() ? true : this.auth.redirectToLoginTree();
  }
}

@Injectable({ providedIn: 'root' })
export class RoleGuard implements OrderedGuard {
  constructor(private roles: RoleService) {}
  canActivate(route: ActivatedRouteSnapshot): boolean {
    return this.roles.hasRequiredRoles(route.data['roles']);
  }
}

@Injectable({ providedIn: 'root' })
export class BusinessGuard implements OrderedGuard {
  constructor(private business: BusinessService) {}
  async canActivate(): Promise<boolean | UrlTree> {
    const ok = await this.business.checkPrerequisites();
    return ok ? true : this.business.redirectToPrereqTree();
  }
}

2) Route configuration with ordered guards


{
  path: 'secure-area',
  component: SecureComponent,
  data: { roles: ['ADMIN', 'EDITOR'] },
  canActivate: [
    OrderedAsyncGuardUtils.orderedAsyncGuards([AuthGuard, RoleGuard, BusinessGuard])
  ]
}

Result:

  1. AuthGuard runs first.
  2. If true, RoleGuard runs next.
  3. If true, BusinessGuard runs last.
  4. If any guard returns false or UrlTree, execution stops and that value is returned.

Core Utility Code


function toObservable(
  value: boolean | UrlTree | Observable<boolean | UrlTree> | Promise<boolean | UrlTree>
): Observable<boolean | UrlTree> {
  if (isObservable(value)) return value as Observable<boolean | UrlTree>;
  if (value instanceof Promise) return from(value);
  return of(value);
}

export class OrderedAsyncGuardUtils {
  static orderedAsyncGuards(guards: GuardClass[]): CanActivateFn {
    return (route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean | UrlTree> => {
      const instances = guards.map(g => inject(g)) as unknown as OrderedGuard[];
      return from(instances).pipe(
        concatMap(guard => toObservable(guard.canActivate(route, state))),
        takeWhile(result => result === true, true),
        last()
      );
    };
  }
}

메타데이터
post_id
9fa5367fa848
slug
execute-angular-guards-sequentially-and-in-order-9fa5367fa848
url
https://medium.com/@anassguendef/execute-angular-guards-sequentially-and-in-order-9fa5367fa848
canonical_url
https://medium.com/@anassguendef/execute-angular-guards-sequentially-and-in-order-9fa5367fa848
author_url
https://medium.com/@anassguendef
status
ok
fetched_at
2026-08-10 19:13:05