angularngrxangular-universalngrx-storeangular-guards

Angular Universal: Get Store in Guard on Server-side using NgRx


I am running an Angular 9 Universal application that uses NgRx for state management. I am also using ngrx-store-localstorage to persist the Store into the user's localStorage.

I am trying to check if user is loggedIn before accessing certain routes with NgRx inside a Guard:

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

    if (isPlatformBrowser(this.platformId)) {
      console.log('browser')
      return this.store.select('user').pipe(
        map(authUser => {
          if (!authUser.id || !authUser.token) {
            console.log(authUser)
            this.router.navigate(['/login'])
            return false
          }
          return authUser.id ? true : false;
        }))
    }
    console.log('server')
    this.router.navigate(['/login'])
    return false
  }

I am doing a platform check since my server does not have access to the store. But this creates unwanted behaviors since it checks twice and sometimes render the login page before rendering the guarded page.

Do you know a way to let my server know about the current State or an alternative way to verify if my user is authenticated?


Solution

  • I ended up using ngx-cookie plugin that makes my guard able to access cookies on the Browser and on the Server: https://github.com/ngx-utils/cookies#servermodulets

    My guard looks like that now:

        canActivate(
            next: ActivatedRouteSnapshot,
            state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
            if (isPlatformBrowser(this.platformId)) {
              var token = this.cookies.getObject('_avoSession')
              if (!token) {
                this.router.navigate(['/login'])
                return false
              }
              console.log(token)
              return true
    
            }
            if (isPlatformServer(this.platformId)) {
              let cookie = this.cookies.getObject('_avoSession')
              if (!cookie) {
                this.router.navigate(['/login'])
                return false
              }
              return true 
            }
    
      }
    

    The platformCheck here is useless since both my server and browser have access to cookies, but if you need some modularity and add specific checks for different use cases, it can be useful.

    You can also verify your jwt by following this example here with Observables.