auth0/auth0-vue

Endless redirection when "Blocked thrid party cookie" is enabled

AloisH opened this issue · 6 comments

AloisH commented

Checklist

  • The issue can be reproduced in the auth0-vue sample app (or N/A).
  • I have looked into the Readme, Examples, and FAQ and have not found a suitable solution or answer.
  • I have looked into the API documentation and have not found a suitable solution or answer.
  • I have searched the issues and have not found a suitable solution or answer.
  • I have searched the Auth0 Community forums and have not found a suitable solution or answer.
  • I agree to the terms within the Auth0 Code of Conduct.

Description

When we enable the option to "block third-party cookies" on Chrome or Edge and if we force the user to log in when he enters the website, it will endlessly redirect the user.

What should happen:
It should only redirect once for login.

Reproduction

  1. Enable "block third-party cookies" on Chrome
  2. Clone auth0-vue-sample
  3. Modify App.vue to force login when the user enters the website
  async created() {
    await this.$auth0.checkSession();
    if (!this.$auth0.isAuthenticated.value) {
        await this.$auth0.loginWithRedirect();
    }
  },
  1. Start the application
  2. You will be endlessly redirected.

Additional context

So far, the only way I found to fix it is to wait 500ms after calling

    await this.$auth0.checkSession();

Example of working version with the sample app

import NavBar from "./components/NavBar.vue";
import Error from "./components/Error.vue";

const delay = (ms: number) => new Promise((res) => setTimeout(res, ms));

export default {
  components: {
    NavBar,
    Error,
  },
  async created() {
    await this.$auth0.checkSession();
    if (!this.$auth0.isAuthenticated.value) {
      // When "Block thrid-party cookies" is enabled the application will endlessly redirect the user.
      // If we wait 500 ms, it will work.
      await delay(500);
      if (!this.$auth0.isAuthenticated.value) {
        await this.$auth0.loginWithRedirect();
      }
    }
  },
};

auth0-vue version

^2.2.0

Vue version

^3.3.4

Which browsers have you tested in?

Chrome, Edge

Hey,

When third party cookies are blocked you will need to use custom domains or refresh tokens. But even when using refresh tokens, it's still recommended to use custom domains.

See: https://github.com/auth0/auth0-vue/blob/main/FAQ.md#1-user-is-not-logged-in-after-page-refresh (this link doesnt exactly describe your situation, but it's also about checkSession)

Regardless, that should not be related to the infinite redirect, or at least not directly. But I think it's still relevant to mention.

The infinite redirect is caused by your own code. Can you try and ensure you only call checkSession when isLoading is false?
That might explain why the 500ms delay works, because there is a time for our SDK to handle the OAuth transaction, which is indicated by isLoading. So as long as isLoading is true, please do not interact with anything but isLoading.

Not using isLoading can be fine, but in situation where you have this kind of code you are showing on page-load, you will need to use isLoading.

Thanks

AloisH commented

Hey !
Thank you for the quick reply.

I just tried waiting that isLoading = false,
but the issue remains.

Here is the code I used

async created() {
    await (this.$auth0 as any).__refreshState();
    console.log(this.$auth0.isLoading.value); // false
    await this.$auth0.checkSession();
    if (!this.$auth0.isAuthenticated.value) {
      await this.$auth0.loginWithRedirect();
    }
  },

Does the SDK have a better function to ensure that isLoading is false ?

What I think is happening is that checkSession will fail due to third party cookies (solved by custom domains or refresh tokens).

Can you verify the following:

async created() {
    await (this.$auth0 as any).__refreshState();
    console.log(this.$auth0.isLoading.value); // false
    console.log(this.$auth0.isAuthenticated.value); // IS THIS TRUE?
    await this.$auth0.checkSession();
    console.log(this.$auth0.isAuthenticated.value); // IS THIS FALSE NOW?
    if (!this.$auth0.isAuthenticated.value) {
      await this.$auth0.loginWithRedirect();
    }
  },

I assume isAuthenticated is true before calling checkSession, and false after. That's confusing but expected when third party cookies are blocked without custom domains or refresh tokens.

If my assumption above is not correct, please reproduce it in https://github.com/auth0-samples/auth0-vue-samples/tree/master/01-Login and I am happy to look at it and see what's going on.

AloisH commented

I just tried your code but isAuthenticated is always false

I found a way to fix it without having to call refreshState()

watch: {
    "$auth0.isLoading.value": async function () {
      await this.$auth0.checkSession();
      if (!this.$auth0.isAuthenticated.value) {
        await this.$auth0.loginWithRedirect();
      }
    },
  },

I will make a repo that reproduce the bug !

Not sure I understand what bug you want to report if you say the above code fixes it. As that's exactly what you need, to wait for isLoading to be false.

I don't think the above code shows a bug, but is exactly what you want.

There are several ways to wait for isLoading. Generally, I move all code for Auth0 into a certain sub-root component that I ensure is not rendered until isLoading is false using v-if. That avoids watches like above. However, watches like u have work fine as well.

Something like <sub-root-that-holds-everything-for-auth0 v-if="!$auth0.isLoading"></sub-root-that-holds-everything-for-auth0> should work.

So yeah, I do use the SDK outside of that sub-root, but only for isLoading.

Technically, it's also okay to use isAuthenticated and user outside of that sub-root component, as long as you rely on Vue's reactivity as the values only reflect the accurate state when isLoading is false.

But that doesnt count for things like checkSession, loginWithRedirect, getAccessTokenSilently, ...

Closing as I think it's answered. Happy to continue the conversation as needed.