Search code examples
vue.jsvuejs2nuxt.jsnuxt-auth

Nuxt fetchUser Auth function isn't reactive and requires a hard refresh


Using Nuxt 2.15.3, with a Rails backend.

I'm trying to create a Google OAuth workflow in my app, and I'm having some trouble with the steps after getting the access code. Once the user authenticates with Google and gets redirected back with the access code in the URL params, I send a request to my own backend to save the access/refresh tokens in the User model.

NOTE: this google Auth flow is separate from my normal app sign-in/sign-up flow. I'm only using some Google APIs, so this has nothing to do with making a user account via Google OAuth, I'm only requesting access to some APIs in the user's Google account, namely the My Business API.

Now, my backend has a boolean google_authenticated field on the User table which gets set to true if the access/refresh token exists, which automatically gets sent to Nuxt as $auth.user.google_authenticated. This feature works fine, but my problem is that the page where the users get redirected to has a v-if that checks for this google_authenticated flag.

The template looks like this, obviously simplified for the sake of the question

<template>
  <div v-if="googleAuthenticated">...</div>
  <div v-else><a href="googleapis.com">Authenticate</button></div>
</template>
export default {
  data() {
    return {
      googleAuthenticated: this.$auth.user.googleAuthorized,
    };
  },
  async mounted() {
    const accessCode = this.$route.query.code;

    await this.$axios
      .post("/users/google_oauth", {
        access_code: accessCode,
      })
      .then((response) => {
        this.$auth.fetchUser();
      });
  }
}

So as you can see, what I'm trying to do is to refresh the $auth.user.googleAuthorized automatically on mount when the user gets to the page with the code in the URL params. The problem is that $auth.user doesn't seem to be reactive, and the user needs to either navigate to another page or refresh the current page to get these changes to show up and for the v-if to trigger and to show the other div.

I can see from the dev console that the fetchUser() method does indeed get called, and I can see from the Vuex store that the auth/SET function has been called and that the $auth.user.googleAuthorized flag is set to true as well.

According to the Nuxt Docs, the $auth module is reactive, but I'm failing to see it. What can I do here to make these changes stick properly?


Solution

  • So it turns out it's a race condition (sorta).

    What's happening is that once I tell my own API to get the access tokens from Google, that request obviously takes some non-zero amount of time. As such, Vue is waiting to get the 200 from my own API indicating that I've fetched the access token and can continue with using Google APIs.

    So basically, by the time Nuxt is calling fetchUser() again, it's actually getting the user without the googleAuthorized flag set to true, because that just happens a tiny bit too slowly. It's not really something noticeable when you're just looking at dev tools though, since everything seems to be happening instantaneously more or less, but the timings are extremely close, which is the reason why it would sometimes work, and other times it wouldn't without a refresh.