Infinite requests when piping auth.user$ in angular/auth-o

I recently switched to @auth0/auth0-angular in two of my projects, where you don’t have the “self-written” AuthService anymore, but register everything in the app.module.ts

AuthModule.forRoot({
  domain: '<MY-DOMAIN>.auth0.com',
  clientId: 'XXXXXXXXX',
  useRefreshTokens: true,
  cacheLocation: 'localstorage'
})

I am using @auth0/auth0-angular 1.3.2 and @auth0/auth0-spa-js 1.13.6

The problem now is that, unlike before, if I pipe the user via the AuthService imported from auth0-angular, it results in infinite requests to the server. Usually, I do something like this:

this.auth.user$.pipe(
    user => this.apiService.getStuff(user.sub)
);

This now results in an infinite loop:

Why is that? What happens in the AuthService by piping the user other than retrieving the user information? Or in other words, how should I get the information otherwise?

Strangely, in other places, this has no effect, like in my nav-component, where I display the username if its logged in

this.user$ = this.auth.user$.pipe(
  map((user: AuthUser) => user)
);

{{ (user$ | async)?.nickname }}

Also, my workaround at the moment is to have a wrapper component, where I assign the userId to an Observable

  userId$: Observable<string>;

  constructor(private auth: AuthService) { }

  ngOnInit(): void {
    this.userId$ = this.auth.user$.pipe(
      map((user: AuthUser) => user.sub.split('|')[1])
    );
  }

and pass that down

<app-my-team
  [userId]="userId$ | async"
></app-my-team>

where then I use that userId to do the same API-Request like the first one mentioned. In the end, this should have the same effect, or am I missing something?

Hi.

This problem is a side effect of a known problem we have in our SDK: Consider only emitting user$ and idTokenClaims$ if they changed · Issue #105 · auth0/auth0-angular · GitHub

The user$ observable might emit more than you would expect, even more so it looks like it is emitting everytime the interceptor is being used. This is something we should fix in the SDK.

However, even when fixing that, it might still be useful to add a distinctUntilChanged like so:

this.auth.user$.pipe(
    map(user => user.sub),
    distinctUntilChanged(),
    switchMap(sub => this.apiService.getStuff(sub))
);

Another work around could be to use take(1):

this.auth.user$.pipe(
    filter(user => Boolean(user)),
    take(1),
    switchMap(user => this.apiService.getStuff(user.sub))
);

Let me know if that doesn’t help.

1 Like

Thanks for helping with this one @frederik.prijck!