Search code examples
javascriptangulartypescriptangular7auth0

Auth0 angular 7 login redirect loop


I am using auth0 to configure my angular 7 app with auth. I followed the quickstart guide to get up and running. The only thing I added in addition to the auth.service.ts file is:

  getTokenSilently$(options?): Observable<string> {
    return this.auth0Client$.pipe(
      concatMap((client: Auth0Client) => from(client.getTokenSilently(options)))
    );
  }

to support the HTTP interceptor:

import { Injectable } from '@angular/core';
import {
  HttpRequest,
  HttpHandler,
  HttpEvent,
  HttpInterceptor
} from '@angular/common/http';
import { AuthService } from './auth.service';
import { Observable, throwError } from 'rxjs';
import { mergeMap, catchError } from 'rxjs/operators';

@Injectable({
  providedIn: 'root'
})
export class InterceptorService implements HttpInterceptor {

  constructor(private auth: AuthService) { }

  intercept(
    req: HttpRequest<any>,
    next: HttpHandler
  ): Observable<HttpEvent<any>> {
    return this.auth.getTokenSilently$().pipe(
      mergeMap(token => {
        const tokenReq = req.clone({
          setHeaders: { Authorization: `Bearer ${token}` }
        });
        return next.handle(tokenReq);
      }),
      catchError(err => throwError(err))
    )
  }
}

The other thing I did differently is that my app does not have a login button, when the app starts up it trys to go to the home page which has an auth guard:

import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree, CanActivate } from '@angular/router';
import { Observable } from 'rxjs';
import { AuthService } from './auth.service';
import { tap } from 'rxjs/operators';

@Injectable({
  providedIn: 'root'
})
export class AuthGuard implements CanActivate {

  constructor(private auth: AuthService) {}

  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): Observable<boolean> | Promise<boolean|UrlTree> | boolean {
    return this.auth.isAuthenticated$.pipe(
      tap(loggedIn => {
        if (!loggedIn) {
          this.auth.login(state.url);
        }
      })
    );
  }

}

so it automatically calls the login so the user gets redirected to auth0. Once they enter their creds it then redirects them back to the home page. Then all of a sudden the auth.service.ts service is loaded again and the auth guard has fired again and it fires the login function again. This seems to just keep on looping.

Any idea why it just keeps on looping?


Solution

  • Replace your Guard method by this one :

        canActivate(
            next: ActivatedRouteSnapshot,
            state: RouterStateSnapshot
        ): Observable<boolean> | Promise<boolean | UrlTree> | boolean {
            return this.auth.isAuthenticated$.pipe(
                delay(1000),
                tap(loggedIn => {
                    if (!loggedIn) {
                        this.auth.login(state.url);
                    }
                })
            );
        }
    

    The problem was that loggedIn is still at false, even after a successful login. I am aware that this is not a clean or pretty solution.
    I modestly think that the Auth0 Angular sample needs some fixes.