Angular AuthGuard - NgRx - Universal on reload redirection

Viewed 139

The problem is with Angular Universal, if I build app without Universal It's working fine but with Angular Universal this is the problem.

I'm using angular with ngrx and Angular Universal, on every reload I'm sending request to the backend then retreiveing user data. If route is protected with auth guard on reload if user is logged in first it redirects to /login then after 0.5 seconds redirects to protected route, data is loaded everything works fine, but why It's showing /login first ?

AuthGuard

  canActivate(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {

      return this.store.select(fromAuth.selectAuthState).pipe(
        map(authState => authState.isInitializing),
        filter((isInit) => !isInit),
        tap((data) => console.log(data)),
        switchMap(() => {
          return this.store.select(fromAuth.selectAuthState).pipe(
            map(authState => authState),
            map((isAuth) => {
              console.log(isAuth);
              if (isAuth.user) return true;
              return this.router.createUrlTree(['/login'], { queryParams: { returnUrl: state.url } });
            }),
            take(1)
            );
        })
      );

Initial state in Ngrx/store

export const initialState: State = {
  isAuthenticated: false,
  isInitializing: true

On login success and on login fail isInitializing is set to false

  on(AuthActions.logInSuccess, (state) => {
    return {
      isInitializing: false,
      isAuthenticated: true,
    };
  }),

I'm dispatching isLoggedIn action in APP_INITIALIZER

export function appInitializerFactory(
  store: Store<any>
) {
  return () => {
          store.dispatch(AuthActions.isLoggedIn());
  };
}

  providers: [
    {
      provide: APP_INITIALIZER,
      useFactory: appInitializerFactory,
      deps: [Store],
      multi: true
  }
  ]

Inside Auth Effects

  isLoggedIn$ = createEffect(() =>
    this.actions$.pipe(
      ofType(AuthActions.isLoggedIn),
      switchMap(() => {
        return this.authService.isLoggedIn().pipe(
          switchMap((user: any) => {
            return [
              AuthActions.logInSuccess({ token: user.token, name: user.data.user.name, email: user.data.user.email, id: user.data.user._id, likedProperties: [...user.data.user.likedPropertiesSell, ...user.data.user.likedPropertiesRent], myProfileInformations: userProfile })]
          }),
          catchError(err => {
            return of(AuthActions.logInFail({ error: `code ${err.status}` }))
          }
          )
        );
      })
    )
  );

Console log from Auth Guard

2020-12-24T14:01:53.070535+00:00 app[web.1]:   isAuthenticated: false,
2020-12-24T14:01:53.070535+00:00 app[web.1]:   user: null,
2020-12-24T14:01:53.070536+00:00 app[web.1]:   errorMessage: 'code undefined',
2020-12-24T14:01:53.070537+00:00 app[web.1]:   likedProperties: null,
2020-12-24T14:01:53.070537+00:00 app[web.1]:   following: null,
2020-12-24T14:01:53.070538+00:00 app[web.1]:   followingListLoaded: false,
2020-12-24T14:01:53.070538+00:00 app[web.1]:   myProfileInformations: null,
2020-12-24T14:01:53.070539+00:00 app[web.1]:   isInitializing: false
2020-12-24T14:01:53.070539+00:00 app[web.1]: }

So store is setting isInitializing to false before user data is retreived and I really don't know why errorMessage exists there, in redux store logInFail() is never dispatched

0 Answers
Related