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

getTokenSilently throws "Login required" with Safari #623

Closed
pleportz opened this issue Nov 3, 2020 · 3 comments
Closed

getTokenSilently throws "Login required" with Safari #623

pleportz opened this issue Nov 3, 2020 · 3 comments
Labels
bug report This issue reports a suspect bug or issue with the SDK itself

Comments

@pleportz
Copy link

pleportz commented Nov 3, 2020

Problem description with reproduction steps

Hi! I'm using "@auth0/auth0-spa-js": "^1.13.1" in a "next": "9.5.5" app. I'm trying to authenticate with the new Universal Login. It works fine with Chrome and Firefox browsers, but not with Safari (I'm currently testing with Safari 14.0).

Here is what I'm currently trying:

  1. Instanciate Auth0 client with
new Auth0Client({
  domain: process.env.NEXT_PUBLIC_AUTH0_DOMAIN!,
  client_id: process.env.NEXT_PUBLIC_AUTH0_CLIENT_ID!,
  redirect_uri: process.env.NEXT_PUBLIC_AUTH0_CALLBACK_URL,
  useRefreshTokens: true,
  cacheLocation: 'localstorage',
})
  1. On login button click, trigger :
const onLoginButtonClick = async (): Promise<void> => {
    await loginWithRedirect({});
};
  1. User types email / password on new Universal Login page and gets redirected to process.env.NEXT_PUBLIC_AUTH0_CALLBACK_URL

  2. Retrieve the access token to build the authorization header to make an API call:

  let accessToken = '';
  try {
    accessToken = await auth0Client.getTokenSilently({
      audience: process.env.NEXT_PUBLIC_AUTH0_AUDIENCE,
      scope: AUTH0_SCOPE,
      ignoreCache: false,
    });
  } catch (error) {
    console.warn('getTokenSilently:', error);
    try {
      accessToken = await auth0Client.getTokenWithPopup({
        audience: process.env.NEXT_PUBLIC_AUTH0_AUDIENCE,
        scope: AUTH0_SCOPE,
      });
    } catch (e) {
      console.warn('getTokenWithPopup:', e);
    }
  }
  return {
    headers: {
      Authorization: `Bearer ${accessToken}`,
    },
  };

With Safari, both getTokenSilently and then getTokenWithPopup fail, with the following errors:

  • getTokenSilently: Error: Login required
  • getTokenWithPopup: Error: Could not open popup

What was the expected behavior?

With useRefreshTokens and localStorage enabled, I thought getTokenSilently would workaround the Safari ITP and succeed in retrieving the access token.
I should not even need to fallback to getTokenWithPopup, am I correct?

I would like to make it work without using custom domains because they require a paid plan. By the way, do you know when Chrome and Firefox will also implement ITP?

Similar issues

Resources I've been around

@pleportz pleportz added the bug report This issue reports a suspect bug or issue with the SDK itself label Nov 3, 2020
@stevehobbsdev
Copy link
Contributor

@pleportz I notice you are specifying scope and audience values to getTokenSilently but not to the Auth0Client constructor. Can you try specifying these values in the constructor instead and remove from the getTokenSilently call?

new Auth0Client({
  domain: process.env.NEXT_PUBLIC_AUTH0_DOMAIN!,
  client_id: process.env.NEXT_PUBLIC_AUTH0_CLIENT_ID!,
  redirect_uri: process.env.NEXT_PUBLIC_AUTH0_CALLBACK_URL,
  scope: AUTH0_SCOPE,
  audience: audience: process.env.NEXT_PUBLIC_AUTH0_AUDIENCE,
  useRefreshTokens: true,
  cacheLocation: 'localstorage',
})

I suspect you're getting a cache miss internally when you specify scope and audience values to getTokenSilently that it doesn't already know about. If you only have one constant audience and scope, specify them in the constructor so that they're used for both the login calls and in getTokenSilently.

The reason it works though in Chrome and Firefox is that those browsers have the ability to fallback to using an iframe, whereas Safari doesn't, because the cookies are being blocked due to ITP.

Let me know if this solves your problem.

@pleportz
Copy link
Author

pleportz commented Nov 3, 2020

@stevehobbsdev thanks for your help. I applied your suggested modifications.
It turns out the root cause was a race condition in my code: getTokenSilently was called before handleRedirectCallback, therefore the access token was not written in the cache yet and getTokenSilently could not retrieve it.

Again, thanks for your help an sorry for the inconvenience

@pleportz pleportz closed this as completed Nov 3, 2020
@s-kennedy
Copy link

It turns out the root cause was a race condition in my code: getTokenSilently was called before handleRedirectCallback, therefore the access token was not written in the cache yet and getTokenSilently could not retrieve it.

@pleportz I had the same issue, thanks for pointing me in the right direction!

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

3 participants