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

Unable to call getTokenSilently concurrently #109

Closed
Tazaf opened this issue Jul 24, 2019 · 8 comments · Fixed by #238
Closed

Unable to call getTokenSilently concurrently #109

Tazaf opened this issue Jul 24, 2019 · 8 comments · Fixed by #238

Comments

@Tazaf
Copy link

Tazaf commented Jul 24, 2019

Hi!

I'm having an error in the console when creating the Auth0 client using createAuth0Client().

The error is the following:

> ERROR TypeError: Cannot read property 'close' of undefined
    at o (auth0-spa-js.production.js:formatted:1)
    at ZoneDelegate.invokeTask (zone-evergreen.js:391)
    at Object.onInvokeTask (auth0-spa-js.production.js:formatted:1)
    at ZoneDelegate.invokeTask (zone-evergreen.js:390)
    at Zone.runTask (zone-evergreen.js:168)
    at ZoneTask.invokeTask [as invoke] (zone-evergreen.js:465)
    at invokeTask (zone-evergreen.js:1603)
    at globalZoneAwareCallback (zone-evergreen.js:1640)

On the beautyfied production code, the error points to this line:

o = function(i) {
  // Below is the culprit, apparently, 'i.source' is undefined
  i.origin == m && i.data && "authorization_response" === i.data.type && (i.source.close(),
  i.data.response.error ? t(i.data.response) : e(i.data.response),
  clearTimeout(n),
  window.removeEventListener("message", o, !1),
  window.document.body.removeChild(r))
};

And the code that's calling the createAuth0Client() function is this one (pretty much the exact same as the Angular Login Tutorial):

// This is a method of my AuthService
async getAuth0Client(): Promise<Auth0Client> {
  if (!this.auth0Client) {
    console.log("AuthService - generating new Auth0Client");
    this.auth0Client = await createAuth0Client(environment.auth0);
    console.log("AuthService - new Auth0Client", this.auth0Client);

    // Provide the current value of isAuthenticated
    this.isAuthenticated.next(await this.auth0Client.isAuthenticated());

    // Whenever isAuthenticated changes, provide the current value of `getUser`
    this.isAuthenticated
      .subscribe(async isAuthenticated => await this.updateUserProfile(isAuthenticated));
  }
  return this.auth0Client;
}

Note that this error does not prevent the client to be effectively created and functionning. But it's still an unwanted error 😄

Also, some other people seem to have the same kind of issue, see this thread in the Auth0 Community Forums

@luisrudge
Copy link
Contributor

This is probably happening because the iframe was already closed 🤔 Can you inspect dev tools and see if you're sending two requests to the /authorize endpoint?

@gosuhiman
Copy link

I've got the same problem, and there are 2 requests sent to /authorize.

@rkuprin
Copy link

rkuprin commented Jul 29, 2019

Same problem, two requests. Happens only if you refresh a page after sign-in (I'm using Auth0 with Angular SPA), without refreshing it works fine and sends just one request.

@luisrudge
Copy link
Contributor

@gosuhiman @rkuprin Is it possible that you have two instances of the client? can you build a repro to help me identify why are you seeing two requests?

@max-eb
Copy link

max-eb commented Aug 7, 2019

Same problem if you write code like this:

class Auth { 
 getAuthClient = () => new Promise((resolve) => {
    if (this.auth0Client) {
      return resolve(this.auth0Client);
    }

    return resolve(createAuth0Client({
    domain: DOMAIN,
    client_id: CLIENT_ID,
    connection: DATABASE,
    audience: AUDIENCE,
    redirect_uri: ORIGIN,
    }).then(auth0Client => resolve(auth0Client)));
  });

  getUserInfo = async () => {
    const auth0Client = await this.getAuthClient();
    return auth0Client.getUser();
  }
}

If you call getUserInfo in several places in your project, after refreshing page, it will invoke function createAuth0Client several times.
In function createAuth0Client, it will call getTokenSilently. That is, if you invoke createAuth0Client multiple times, it will use a same iframe window(not sure). Once a tread called close, the other thread will fail.
So I changed the code to this:

class Auth {
  constructor() {
    this.setUp();
  }

  setUp = async () => createAuth0Client({
    domain: DOMAIN,
    client_id: CLIENT_ID,
    connection: DATABASE,
    audience: AUDIENCE,
    redirect_uri: ORIGIN,
  }).then((auth0Client) => {
    this.auth0Client = auth0Client;
  });

  getAuthClient = () => new Promise((resolve) => {
    const checkAuth0Ready = setInterval(() => {
      if (this.auth0Client) {
        resolve(this.auth0Client);
        clearInterval(checkAuth0Ready);
      }
    }, 500);

    setTimeout(() => clearInterval(checkAuth0Ready), 10000);
  });

  getUserInfo = async () => {
    const auth0Client = await this.getAuthClient();
    return auth0Client.getUser();
  }

And it doesn't throw exceptions now.

@Schmaga
Copy link

Schmaga commented Aug 7, 2019

This is a duplicate of my post from the auth0 community forum, but I hope it might help someome:

I think I might have found the problem. Because of the observables and multiple subscriptions, there might have been concurrency issues or multiple instances of the Auth0Client. I got rid of the error by doing it this way:

Create the client as shared observable in a similar way like you proposed in your updated angular quickstart:

  private auth0Client$ = (from(createAuth0Client(this.config))).pipe(
    shareReplay(1), // Every subscription receives the same shared value
  );

And using it using a piped observable.

isAuthenticated() {
 return this.auth0Client$.pipe(switchMap(client => {
   return from(client.isAuthenticated());
}));
}

This has solved the error for me.

@luisrudge
Copy link
Contributor

Thanks for posting this @Schmaga! We recently upgraded our Angular Quickstart with the shareReplaymethod as well. Here's our take on a great AuthService: https://auth0.com/docs/quickstart/spa/angular2/01-login#add-an-authentication-service

@Tazaf
Copy link
Author

Tazaf commented Aug 8, 2019

@luisrudge I've seen that! And I got to say that this is a waaaay better AuthService than the one before 👍
(By the way, I did not run onto this thread issue)

@luisrudge luisrudge changed the title createAuth0Client raises a TypeError "Cannot read property 'close' of undefined" Unable to call getTokenSilently concurrently Oct 4, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
6 participants