angularangular-ssrangular18

Angular SSR: CanActivate Guard Redirects to Error Page Before Loading Target Component


I have a simple routing guard in my Angular application that uses "@angular/ssr": "^18.0.5" which check for the "redirect" query param.

export const redirectGuard: CanActivateFn = (_, state): boolean | UrlTree => {
  const hasRedirect = state.root.queryParams['redirect'];
  const router = inject(Router);
  if(!hasRedirect) {
    return router.createUrlTree(['/error']);
  }

  return true;
};

The app.routes.ts:

export const APP_ROUTES: Routes = [
  {
    path: '',
    canActivate: [redirectGuard],
    loadComponent: () =>
      import('./features/login/login.component').then((m) => m.LoginComponent),
  },
  ...
    {
    path: 'error',
    loadComponent: () =>
      import('./features/error/error.component').then((m) => m.ErrorComponent),
  }
]

When I try to reach the application like: http://localhost:4000/?redirect=https:%2F%2FXXX.XXX-XXX.XXX.XXX%2F the page behave like this:

enter image description here

The error page is shown for a while and then the guard process and show the LoginComponent.


Solution

  • It happens since when in the server, it redirects to error page, then the guard runs on the browser, so it goes to login again. To solve this, perform the redirect only on the browser.

    import { inject, Inject, Injectable, PLATFORM_ID } from '@angular/core';
    import { isPlatformBrowser, isPlatformServer } from '@angular/common';
    
    export const redirectGuard: CanActivateFn = (_, state): boolean | UrlTree => {
      const platformId = inject(PLATFORM_ID);
      const hasRedirect = state.root.queryParams['redirect'];
      const router = inject(Router);
      if(!hasRedirect && isPlatformBrowser(platformId)) {
        return router.createUrlTree(['/error']);
      }
    
      return true;
    };