Search code examples
angularrxjsgoogle-signinangular-social-login

Angular Social Login (with Google) + Angular Guards


I'm trying to implement an Angular Guard using the Angular Social Login npm package:

@Injectable({
  providedIn: 'root',
})
export class LoginGuard implements CanActivate {
  constructor(private router: Router, private authService: SocialAuthService) {}

  canActivate(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): Observable<boolean> {
    console.log('guard');
    return this.authService.authState.pipe(
      map((socialUser: SocialUser) => {
        console.log('map');
        return !!socialUser;
      }),
      catchError((error) => {
        console.log(error);
        return of(false);
      })
    );
  }
}

I can see guard being printed to the console. However, I can't see map printed to the console. Why?

If I do:


@Injectable({
  providedIn: 'root',
})
export class LoginGuard implements CanActivate {
  constructor(private router: Router, private authService: SocialAuthService) {}

  canActivate(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): Observable<boolean> {
    console.log('guard');
    return new Observable<boolean>((subscriber) => {
      console.log('subscriber');
      subscriber.next(true);
    });
  }
}

I can see subscriber being printed to the console.

What am I doing wrong?

I want to be able to add this Guard to a route. If a user is not logged in, it would be redirected to a login page (I know I'm not yet implementing that logic; I've tried and failed since it seems I'm not getting an Observable with values?). Note that I'm using Google as a provider for this:

@NgModule({
  declarations: [
    AppComponent,
    IndexPageComponent,
    SearchPageComponent,
    InputKeywordsComponent,
    DisplayNewsListComponent,
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    ReactiveFormsModule,
    HttpClientModule,
    SocialLoginModule,
  ],
  providers: [
    {
      provide: 'SocialAuthServiceConfig',
      useValue: {
        autoLogin: false,
        providers: [
          {
            id: GoogleLoginProvider.PROVIDER_ID,
            provider: new GoogleLoginProvider(
              'superVerySecret'
            ),
          },
        ],
      } as SocialAuthServiceConfig,
    },
  ],
  bootstrap: [AppComponent],
})
export class AppModule {}

And the routing module:

const routes: Routes = [
  { path: '', component: IndexPageComponent },
  { path: 'search', component: SearchPageComponent, canActivate: [LoginGuard] },
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule],
  providers: [LoginGuard]
})
export class AppRoutingModule {}

PS1: I can login just fine.

PS2:


Solution

  • Kudos to @msmiechowski for helping me reaching a solution in this GitHub issue.

    My solution:

    // login.guard.ts
    
    @Injectable({
      providedIn: 'root',
    })
    export class LoginGuard implements CanActivate {
      constructor(private router: Router, private loginService: LoginService) {}
    
      canActivate(
        route: ActivatedRouteSnapshot,
        state: RouterStateSnapshot
      ): Observable<boolean> {
        if (this.loginService.checkAuthState()) {
          return of(true);
        } else {
          this.router.navigateByUrl('/');
          return of(false);
        }
      }
    }
    
    // login.service.ts
    
    // ...
    
    checkAuthState(): boolean {
      let flag = false;
      this.authService.authState.subscribe({
        next: (socialUser: SocialUser) => {
          if (socialUser) {
            flag = true;
          }
        },
        error: (error) => {
          console.log(error);
        },
        complete: () => {
          console.log('Complete!');
        },
      });
      return flag;
    }
    
    // ...