No More Posting New Topics!

If you have a question or an issue, please start a thread in our Github Discussions Forum.
This forum is closed for new threads/ topics.

Navigation

    Quasar Framework

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search

    Loading firebase user identity before everything else?

    Help
    auth firebase vuex
    2
    5
    1386
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • D
      darshie last edited by

      Currently doing a SSR app with Quasar v1 CLI & Firebase for auth (via Vuex). I have Firebase loaded in boot. Auth flow (simplified): if logged in, user can access anything under “player” layout (multiple pages). If not logged in, user can only see /login. Redirection accomplished via Router.beforeEach nav guard in router’s index.js.

      If just clicking links (router.push), everything works great. However, when reloading the page or trying to access an auth restricted page, it’ll bounce the logged-in user back to /login. From /login, clicking a nav link will work just fine again.

      I think the problem is on reload/URL entry, the entire state/js is wiped clean. List below of the fixes I tried. Long story short, though, I noticed that Firebase’s initial onAuthStateChange requests were returning null until the page fully loaded, and then user identity would be properly loaded to the state & returned. No matter how early I tried to tuck the Firebase listener into the flow, I got the same results. I thought it was Firebase’s problem until I followed Tobias’ suggestions link here for persistent storage via localstorage / cookies, and while I could get them working, my store.state.user.user wouldn’t update until redirection to /login had already occurred. Before then, store.state.user.user returned null. After, it properly read from localStorage.

      I’ve tried putting beforeCreated listeners on the relevant pages/layouts to get initial login state:

      mainAuthLayout.vue

      beforeCreate() {
        this.$auth.onAuthStateChanged(user => {
          if (user) {
            user.getIdToken().then(idToken => {
              this.$store.dispatch("user/setUser", idToken)
              this.$router.push("/home/main")
            })
          } else {
            this.$store.dispatch("user/setUser", null)
          }
        });
      }
      

      Didn’t work. I tried putting onAuthStateChange / getUser methods in the firebase boot file

      boot/firebase.js

      import firebase from "firebase/app"
      import "firebase/auth"
      import config from "./env.json"
      
      export const fireApp = !firebase.apps.length ? firebase.initializeApp(config) : firebase.app() 
      
      export const AUTH = fireApp.auth();
      
      export default ({ store, Vue }) => {
      
        AUTH.onAuthStateChanged(user => {
          if (user) {
            user.getIdToken().then(idToken => {
              store.dispatch("user/setUser", idToken);
            });
          } else {
            store.dispatch("user/setUser", null);
          }
        });
        
        Vue.prototype.$auth = AUTH;
      }
      

      That also didn’t work. I tried a pre-fetch on App.vue (basically the same code), which also didn’t work. In all of this the same problem: redirection to /login before store / $auth ever recognized that the user was already logged in.

      Incidentally:
      router/index.js

      Router.beforeEach((to, from, next) => {
        const currentUser = store.state.user.user
        const requiresAuth = to.matched.some(record => record.meta.requiresAuth)
      
        if (requiresAuth && !currentUser) next("/")
        else next()
      })
      

      There’s no problem if I put my redirect logic as a .then(this.$router.push) in the pages themselves, but that is somewhat inelegant as it flashes the pages before redirection. Alternatively I could redirect users to a loading screen for a pretty short period of time which then routes them to the proper page once auth/store has had a chance to kick in, but I’d like to avoid if possible.

      Any help or directional feedback would be so welcome. Even just suggestions of where I could be looking / reading more. I’ve thrown 6 hours at this already, happy to throw more. Just wanted to see if any of you knowledgeable folks would be able to quickly spot something I was missing. 🙂

      1 Reply Last reply Reply Quote 0
      • T
        turigeza last edited by turigeza

        @darshie The way I solved it is by initialising the state from local storage in the Router.beforeEach(

        mutation.js file is like

        import { LocalStorage } from 'quasar';
        var local = LocalStorage;
        
        export function init (s, p) {
            s.user = local.getItem('user');
            s.hash = local.getItem('hash');
            s.session_id = local.getItem('session_id');
            // what ever else you need to read from local storage do it here
        }
        
        

        My router/index.js file is like

        import Vue from 'vue';
        import VueRouter from 'vue-router';
        import routes from './routes';
        
        Vue.use(VueRouter);
        
        export default function ({ store, ssrContext }) {
            const router = new VueRouter({
                scrollBehavior: () => ({ y: 0 }),
                routes,
                mode: process.env.VUE_ROUTER_MODE,
                base: process.env.VUE_ROUTER_BASE
            });
        
            // initialise state
            store.commit('init');
        
            router.beforeEach((to, from, next) => {
                // non public pages should only be visible to users logged in
                if (!to.meta.public && !store.state.user) {
                    next({
                        path: '/',
                        query: { redirect: to.fullPath }
                    });
                    return;
                }
        
                next();
            });
        
            return router;
        }
        
        

        Basically you look into local storage before you route the user.

        1 Reply Last reply Reply Quote 0
        • D
          darshie last edited by

          I think this should work, but I’m getting the error

          UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 4): TypeError: local.getItem is not a function

          …and I don’t have the foggiest how to address it. Is it possibly because I’m using SSR? I don’t get that issue when running in SPA mode, but then, I don’t get any issues when running in SPA mode–my persistedstate / firebase properly loads before the page, so I don’t get re-directions on refresh.

          1 Reply Last reply Reply Quote 0
          • D
            darshie last edited by

            Okay… got it working with cookies–that’ll have to do for now.

            T 1 Reply Last reply Reply Quote 0
            • T
              turigeza @darshie last edited by

              @darshie the function is called slighly different in 0.17 my code is for v1 forgot to say

              LocalStorage.get.item(key)

              https://quasar-framework.org/components/web-storage.html#Getting-Started

              1 Reply Last reply Reply Quote 0
              • First post
                Last post