Skip to main content
Jet provides three route guards to control access to routes and prevent data loss from navigation.

signedInGuard

Protects routes that require an authenticated user. Redirects to the sign-in page if the user is not authenticated.

Type Signature

export const signedInGuard: CanActivateFn = async (
  _activatedRouteSnapshot,
  routerStateSnapshot,
): Promise<GuardResult>

Parameters

_activatedRouteSnapshot
ActivatedRouteSnapshot
The activated route snapshot (unused in this guard)
routerStateSnapshot
RouterStateSnapshot
The current router state, used to capture the return URL for redirects

Return Value

Returns Promise<GuardResult>:
  • true if the user is authenticated
  • A UrlTree redirecting to /sign-in with a returnUrl query parameter if not authenticated

Behavior

  1. Injects required services: Router, AlertService, LoggerService, and UserService
  2. Attempts to retrieve user claims via userService.getClaims()
  3. If claims exist (user is authenticated), allows navigation
  4. If claims are null, redirects to /sign-in with the current URL as a return parameter
  5. Handles exceptions by logging errors and displaying alerts

Usage

import { signedInGuard } from '@jet/guards/signed-in/signed-in.guard';

const routes: Routes = [
  {
    path: 'profile',
    component: ProfilePageComponent,
    canActivate: [signedInGuard],
  },
];

Real-World Examples

The signedInGuard is used in Jet to protect:
  • /profile - User profile management
  • /update-password - Password update functionality

Source Code

export const signedInGuard: CanActivateFn = async (
  _activatedRouteSnapshot,
  routerStateSnapshot,
): Promise<GuardResult> => {
  const router = inject(Router);
  const alertService = inject(AlertService);
  const loggerService = inject(LoggerService);
  const userService = inject(UserService);

  let guardResult: GuardResult = router.createUrlTree(['/sign-in'], {
    queryParams: { [QueryParam.ReturnUrl]: routerStateSnapshot.url },
  });

  try {
    const { data } = await userService.getClaims();

    if (data !== null) {
      guardResult = true;
    }
  } catch (exception: unknown) {
    if (exception instanceof Error) {
      loggerService.logError(exception);
      alertService.showErrorAlert(exception.message);
    } else {
      loggerService.logException(exception);
    }
  }

  return guardResult;
};

signedOutGuard

Protects routes that should only be accessible to unauthenticated users (e.g., sign-in, sign-up). Redirects to the home page if the user is already authenticated.

Type Signature

export const signedOutGuard: CanActivateFn = async (): Promise<GuardResult>

Parameters

No parameters are used by this guard.

Return Value

Returns Promise<GuardResult>:
  • true if the user is not authenticated
  • A UrlTree redirecting to / if the user is authenticated

Behavior

  1. Injects required services: Router, AlertService, LoggerService, and UserService
  2. Attempts to retrieve user claims via userService.getClaims()
  3. If claims are null (user is not authenticated), allows navigation
  4. If claims exist, redirects to the home page (/)
  5. Handles exceptions by logging errors and displaying alerts

Usage

import { signedOutGuard } from '@jet/guards/signed-out/signed-out.guard';

const routes: Routes = [
  {
    path: 'sign-in',
    component: SignInPageComponent,
    canActivate: [signedOutGuard],
  },
];

Real-World Examples

The signedOutGuard is used in Jet to protect:
  • /reset-password - Password reset page
  • /sign-up - User registration page

Source Code

export const signedOutGuard: CanActivateFn = async (): Promise<GuardResult> => {
  const router = inject(Router);
  const alertService = inject(AlertService);
  const loggerService = inject(LoggerService);
  const userService = inject(UserService();

  let guardResult: GuardResult = router.createUrlTree(['/']);

  try {
    const { data } = await userService.getClaims();

    if (data === null) {
      guardResult = true;
    }
  } catch (exception: unknown) {
    if (exception instanceof Error) {
      loggerService.logError(exception);
      alertService.showErrorAlert(exception.message);
    } else {
      loggerService.logException(exception);
    }
  }

  return guardResult;
};

unsavedChangesGuard

Prevents navigation away from a component with unsaved changes by prompting the user for confirmation.

Type Signature

export const unsavedChangesGuard: CanDeactivateFn<CanComponentDeactivate> = (
  component,
  _activatedRouteSnapshot,
  _currentRouterStateSnapshot,
  nextRouterStateSnapshot,
): GuardResult

Parameters

component
CanComponentDeactivate
The component being deactivated, must implement the CanComponentDeactivate interface with a hasUnsavedChanges() method
_activatedRouteSnapshot
ActivatedRouteSnapshot
The activated route snapshot (unused)
_currentRouterStateSnapshot
RouterStateSnapshot
The current router state (unused)
nextRouterStateSnapshot
RouterStateSnapshot
The next router state, used to check the destination URL

Return Value

Returns GuardResult:
  • true if navigation is allowed (no unsaved changes, or user confirms navigation, or navigating to sign-in)
  • false if the user cancels the confirmation dialog

Behavior

  1. If navigating to /sign-in, allows navigation without checking for unsaved changes
  2. Calls component.hasUnsavedChanges() to check if there are unsaved changes
  3. If there are unsaved changes, displays a browser confirmation dialog with a translated message
  4. Returns the result of the user’s choice

Component Interface

Components using this guard must implement the CanComponentDeactivate interface:
export interface CanComponentDeactivate {
  hasUnsavedChanges(): boolean;
}

Usage

import { unsavedChangesGuard } from '@jet/guards/unsaved-changes/unsaved-changes.guard';
import { CanComponentDeactivate } from '@jet/interfaces/can-component-deactivate.interface';

// In your component
export class ProfilePageComponent implements CanComponentDeactivate {
  hasUnsavedChanges(): boolean {
    return this.profileForm.dirty;
  }
}

// In your routes
const routes: Routes = [
  {
    path: 'profile',
    component: ProfilePageComponent,
    canDeactivate: [unsavedChangesGuard],
  },
];

Real-World Examples

The unsavedChangesGuard is used in Jet to protect:
  • /profile - Prevents losing unsaved profile changes
  • /update-password - Prevents losing password form data

Source Code

export const unsavedChangesGuard: CanDeactivateFn<CanComponentDeactivate> = (
  component,
  _activatedRouteSnapshot,
  _currentRouterStateSnapshot,
  nextRouterStateSnapshot,
): GuardResult => {
  const translocoService = inject(TranslocoService);

  if (nextRouterStateSnapshot.url.startsWith('/sign-in')) {
    return true;
  }

  if (component.hasUnsavedChanges()) {
    return confirm(translocoService.translate('confirmations.youll-lose-unsaved-changes-continue'));
  }

  return true;
};

Dependencies

All guards use Angular’s functional guard approach and inject dependencies using the inject() function:
  • Router - For creating redirect URL trees
  • AlertService - For displaying error messages to users
  • LoggerService - For logging errors and exceptions
  • UserService - For retrieving user authentication claims
  • TranslocoService - For internationalized confirmation messages (unsavedChangesGuard only)

Build docs developers (and LLMs) love