Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Login stalls in some browsers. Page reload is required. #506

Closed
OysteinAmundsen opened this issue Jun 15, 2020 · 9 comments
Closed

Login stalls in some browsers. Page reload is required. #506

OysteinAmundsen opened this issue Jun 15, 2020 · 9 comments
Labels
bug report This issue reports a suspect bug or issue with the SDK itself

Comments

@OysteinAmundsen
Copy link

OysteinAmundsen commented Jun 15, 2020

Describe the problem

I've been following the universal login trail for angular from your docs and I've noticed something strange; when my application requires a login, it will kick off the auth0-spa-js.loginWithRedirect method, but the login page displays a blank page in some browsers. My users need to reload the url before the login page is displayed.

The image below is all my users see before they F5:

No error in console and the same number of network requests done both before and after refresh.
I've tested the same in Firefox, Opera and Edge and it works fine, but in chrome, chrome incognito and Safari it stalls.

This occurred after implementing refresh-tokens to get login to work on Safari (ref. https://community.auth0.com/t/call-to-authorize-fails-on-safari/43477/8)

What was the expected behavior?

I would expect the same result as in other browsers; that the login dialog loads without the need for a manual page refresh.

Reproduction

I've followed the universal login trail for angular, and this is my config:

    createAuth0Client({
      domain: this.authToken.domain,
      client_id: this.authToken.clientId,
      redirect_uri: `${window.location.origin}/callback`,
      audience: `https://${this.authToken.domain}/api/v2/`,
      scope: 'openid profile email',
      useRefreshTokens: true,
      cacheLocation: 'localstorage',
    })

The rest of the service is as described under https://auth0.com/docs/quickstart/spa/angular2/01-login#add-the-authentication-service

I have a route guard which kicks off the login process:

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

Environment

I'm using
@auth0/auth0-spa-js: 1.9.0
@angular/core: 9.1.11

Tested in:

  • Firefox 77.0.1 (64-bit)
  • Opera 68.0.3618.125
  • Chrome 83.0.4103.97
  • Safari 13.1 (15609.1.20.11.8)
@OysteinAmundsen OysteinAmundsen added the bug report This issue reports a suspect bug or issue with the SDK itself label Jun 15, 2020
@adamjmcgrath
Copy link
Member

Hi @OysteinAmundsen - thanks for your report

if yourtenant.auth0.com/login is intermittently returning a blank screen then working when it's refreshed - it sounds like there may be an intermittent issue with serving that url rather than the library that redirects the user to that url.

If it's still happening, can you share a link to your app so we can take a look?

@OysteinAmundsen
Copy link
Author

This is the app: https://logic.noova.no/

@adamjmcgrath
Copy link
Member

Hi, yes - that is odd behaviour.

When I look at the page redirect to the login form, I see that several iframes to the /authorize endpoint are spawned just before the redirect happens.

I managed to get a screenshot of 2 being created:

image

This suggests to me that getTokenSilently is being called multiple times - spawning multiple iframes loading the /authorize url at the same time you're redirecting to the /authorize url - which may explain the odd behaviour you're seeing.

Can you check if you're creating multiple instances of the client, or somehow calling checkSession or getTokenSilently multiple times before calling loginWithRedirect?

@adamjmcgrath
Copy link
Member

I just noticed also that you're loading 2 main js files:

https://logic.noova.no/main-es5.39b377190bcb2ec90b2b.js
https://logic.noova.no/main-es2015.39b377190bcb2ec90b2b.js

They look like they do the same thing, just transpiled differently.

This may explain the 2 iframe calls?

@OysteinAmundsen
Copy link
Author

OysteinAmundsen commented Jun 15, 2020

Angular is creating two bundles, yes. One for browsers with new javascript capabilities, and one for older browsers requiring polyfills. But only one of them should be actively parsed and run.

My chrome installation only loads one of these:
image

I think the nomodule defer attributes makes sure that this is not loaded in browsers able to handle newer javascript.

In addition to the route guard I have in place, I also have a http interceptor which places the bearer token on request headers for our api:

  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))
    );
  }

It is the only place in the application where I invoke getTokenSilently.

I set a logpoint at both the interceptor and the call to loginWithRedirect, and this is the output:
image

This proves that getTokenSilently is in fact invoked 6 times before login hits. Could this be causing the problems you are referring to with multiple iframes? What should I do to avoid this. I need that interceptor for api calls to function...

@donnieregan
Copy link

I am having the same issue with an application that has been working on several months, this problem only started happening in the last 3 weeks.

@OysteinAmundsen
Copy link
Author

I think I fixed it by defering the use of getTokenSilently until I'm sure the login process is complete. The following changes is applied to my auth.service:

  isLoggedIn$ = new BehaviorSubject(false); // NEW

  isAuthenticated$: Observable<boolean> = this.auth0Client$.pipe(
    concatMap((client: Auth0Client) => from(client.isAuthenticated())),
    tap((res: boolean) => {
      this.loggedIn = res;
      this.isLoggedIn$.next(this.loggedIn);  // NEW
    })
  );

  localAuthSetup() {
    const checkAuth$ = this.isAuthenticated$.pipe(
      concatMap((loggedIn: boolean) => {
        if (loggedIn) {
          return this.getUser$();
        }
        return of(loggedIn);
      })
    );
    checkAuth$.subscribe((response: { [key: string]: any } | boolean) => {
      this.loggedIn = !!response;            // NEW
      this.isLoggedIn$.next(this.loggedIn);  // NEW
    })
  }

  getTokenSilently$(options?): Observable<string> {
    // Do not ask for token if we are not logged in yet.
    return this.isLoggedIn$.pipe(
      // Only truthy values will suffice
      filter(isLoggedIn => !!isLoggedIn),
      // Now we are logged in, and can continue to fetch the token.
      switchMap(loggedIn =>
        this.auth0Client$.pipe(concatMap((client: Auth0Client) => from(client.getTokenSilently(options))))
      )
    );
  }

Every line annotated with // NEW is different from the service as described in angular guide for auth0.

What I'm doing here, is providing my own observable for whether or not I'm logged in, and I'm using that observable to defer all calls to getTokenSilently. My observable is resolved once isAuthenticated resolves to "true". This seems to do the trick. The login process will now present me with a login screen without the manual refresh.

If this is the correct fix, your angular guide might need an update. If you have a better suggestion, I'm open.

I'll leave it to you guys to decide if you want to close this issue or not, in case you decide that this is a regression in the product (seeing as other people are just experiencing this problem as well), :-)

@stevehobbsdev
Copy link
Contributor

@OysteinAmundsen We do have this open issue on the Angular sample that I think are running into the same thing. I think this is down to how the sample is configured rather than a regression in the SDK itself. We are planning to upgrade the sample in the future, so this is useful feedback - thanks

@stevehobbsdev
Copy link
Contributor

Closing for now but have recorded feedback internally regarding the Angular sample.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug report This issue reports a suspect bug or issue with the SDK itself
Projects
None yet
Development

No branches or pull requests

4 participants