Can't get currentUser on load

JavascriptFirebaseFirebase Authentication

Javascript Problem Overview


When trying to check if a user is signed in via firebase.auth().currentUser like this:

if (firebase.auth().currentUser === null) {
  console.log('User not signed in');
}

Whenever I refresh the page, or navigate around the above returns null (even though I have just logged in).

The weird thing is, that if I log

console.log(firebase.auth().currentUser) // This returns null
console.log(firebase.auth()) // Here I can inspect the object and currentUser exists...!

I don't really know what's going on here. I'm using React and Redux, but it shouldn't really matter I'd say.

Is there a small delay where the firebase initialises and you can't access the currentUser? If so, how can I see it in the log output of firebase.auth()?

Javascript Solutions


Solution 1 - Javascript

This is a commonly asked question. https://firebase.google.com/docs/auth/web/manage-users You need to add an observer to onAuthStateChanged to detect the initial state and all subsequent state changes,

firebase.auth().onAuthStateChanged(function(user) {
  if (user) {
    // User is signed in.
  } else {
    // No user is signed in.
  }
});

Solution 2 - Javascript

The best way to always have access to currentUser is to use vuex and vuex-persistedstate

//Configure firebase
firebase.initializeApp(firebaseConfig);
//When ever the user authentication state changes write the user to vuex.
firebase.auth().onAuthStateChanged((user) =>{
    if(user){
        store.dispatch('setUser', user);
    }else{
        store.dispatch('setUser', null);
    }
});

The only issue above is that if the user presses refresh on the browser the vuex state will be thrown away and you have to wait for onAuthStateChange to fire again, hence why you get null when you try to access currentUser.

The secret to the above code working all the time is to use vuex-persisted state.

In your store.js file

import Vue from 'vue'
import Vuex from 'vuex'
import firebase from 'firebase/app'
Vue.use(Vuex)
import createPersistedState from "vuex-persistedstate";
export default new Vuex.Store({
    plugins: [createPersistedState()],
  state: {
    user: null
  },
    getters:{
      getUser: state => {
          return state.user;
      }
    },
  mutations: {
    setUser(state, user){
      state.user = user;
    }
  },
  actions: {
    setUser(context, user){
        context.commit('setUser', user);
    },
    signIn(){
        let provider = new firebase.auth.GoogleAuthProvider();
        firebase.auth().signInWithPopup(provider).then(function (result) {
      })
    },
    signOut(){
        firebase.auth().signOut();
    }
  }
})

You can now protect routes in your router as in the code example below.

import Vue from 'vue'
import Router from 'vue-router'
import Home from '@/components/Home'
import Search from '@/components/Search/Search'
import CreateFishingSite from '@/components/FishingSites/CreateFishingSite'
Vue.use(Router);
import store from './store'
import firebase from 'firebase'

let router = new Router({
  routes: [
    {
      path: '/',
      name: 'home',
      component: Home
    },
      {
          path: '/search/:type',
          name: 'Search',
          component: Search
      },
      {
          path: '/fishingsite/create',
          name: 'CreateFishingSite',
          component: CreateFishingSite,
          meta: {
              requiresAuth: true
          }
      }

  ]
})

router.beforeEach(async (to, from, next)=>{
    let currentUser = store.state.user;
    console.log(currentUser);
    let requriesAuth = to.matched.some(record => record.meta.requiresAuth);
    if(requriesAuth && !currentUser){
        await store.dispatch('signIn');
        next('/')
    }else{
        next()
    }
})

Solution 3 - Javascript

A simple way is to add a pending state.

Here is a react example using hooks:

// useAuth.ts

import { useState, useEffect } from 'react'
import { auth } from 'firebase'

export function useAuth() {
  const [authState, setAuthState] = useState({
    isSignedIn: false,
    pending: true,
    user: null,
  })

  useEffect(() => {
    const unregisterAuthObserver = auth().onAuthStateChanged(user =>
      setAuthState({ user, pending: false, isSignedIn: !!user })
    )
    return () => unregisterAuthObserver()
  }, [])

  return { auth, ...authState }
}

// SignIn.tsx

import React from 'react'
import { StyledFirebaseAuth } from 'react-firebaseui'
import { useAuth } from '../hooks'

export default function SignIn() {
  const { pending, isSignedIn, user, auth } = useAuth()

  const uiConfig = {
    signInFlow: 'popup',
    signInOptions: [
      auth.GoogleAuthProvider.PROVIDER_ID,
      auth.FacebookAuthProvider.PROVIDER_ID,
    ],
  }

  if (pending) {
    return <h1>waiting...</h1>
  }

  if (!isSignedIn) {
    return (
      <div>
        <h1>My App</h1>
        <p>Please sign-in:</p>
        <StyledFirebaseAuth uiConfig={uiConfig} firebaseAuth={auth()} />
      </div>
    )
  }

  return (
    <div>
      <h1>My App</h1>
      <p>Welcome {user.displayName}! You are now signed-in!</p>
      <a onClick={() => auth().signOut()}>Sign-out</a>
    </div>
  )
}

Solution 4 - Javascript

If you are looking for a copy and paste Auth route for react with firebase:

const AuthRoute = ({ component: Component, ...rest }) => {
      const [authenticated, setAuthenticated] = useState(false)
      const [loadingAuth, setLoadingAuth] = useState(true)
    
      useEffect(() => {
        firebase.auth().onAuthStateChanged((user) => {
          if (user) {
            setAuthenticated(true)
          } else {
            setAuthenticated(false)
          }
          setLoadingAuth(false)
        })
      }, [])
      return loadingAuth ? 'loading...' : (
        <Route
          {...rest}
          render={props =>
            authenticated ? (
              <Component {...props} />
            ) : (
              <Redirect to={{ pathname: '/user/login' }} />
            )}
        />
    
      )
    }

Solution 5 - Javascript

  // On component load.
  componentDidMount = () => this.getAuthStatus();

  // Get firebase auth status.
  getAuthStatus = () => {
    firebase.auth().onAuthStateChanged((resp) => {

        // Pass response to a call back func to update state
        this.updateUserState(resp);
    });
  }

  // update state
  updateUserState = (resp) => {
     this.setState({
         user: resp
     })
  }

  // Now you can validate anywhere within the component status of a user
  if (this.state.user) { /*logged in*/}

Solution 6 - Javascript

Best approach for this is to use a promise and only instantiate the router after the response, something along the lines of:

store.dispatch('userModule/checkAuth').then(() => {
  // whatever code you use to first initialise your router, add it in here, for example
  new Vue({
    router,
    store,
    render: h => h(App)
  }).$mount('#app')
})

inside the checkAuth action is where you would have your promise, like so:

checkAuth ({ commit }) {
return new Promise((resolve, reject) => {
  firebase.auth().onAuthStateChanged(async (_user) => {
    if (_user) {
      commit('setUser', _user)
    } else {
      commit('setUser', null)
    }
    console.log('current user in checkAuth action:', _user)
    resolve(true)
  })
})

h/t to aaron k saunders - the source of this solution for me.

Solution 7 - Javascript

Promise-wise, there are three options:

// best option

const user1 = await new Promise((resolve: any, reject: any) =>
firebase.auth().onAuthStateChanged((user: any) =>
  resolve(user), (e: any) => reject(e)));

console.log(user1);

// sometimes does not display correctly when logging out

const user2 = await firebase.auth().authState.pipe(first()).toPromise();

console.log(user2);

// technically has a 3rd state of 'unknown' before login state is checked

const user3 = await firebase.auth().currentUser;

console.log(user3);

Solution 8 - Javascript

If you'd like the user to access to a certain page only if he is authenticated and to redirect to the home page if he is not, the following codes might help:

in React: make a component with the following code:

import { onAuthStateChanged } from "@firebase/auth";
import { Route, Redirect } from "react-router-dom";
import { auth } from "../firebase/config";
import { useState, useEffect } from "react";

const GuardedRoute = ({ component, path }) => {
  const [authenticated, setAuthenticated] = useState(false);
  const [authCompleted, setAuthCompleted] = useState(false);
  useEffect(() => {
    onAuthStateChanged(auth, (user) => {
      if (user) {
        setAuthenticated(true);
      } else {
        setAuthenticated(false);
      }
      setAuthCompleted(true);
    });
  }, []);
  return authCompleted ? (
    authenticated ? (
      <Route path={path} component={component} />
    ) : (
      <Redirect to="/" />
    )
  ) : (
    ""
  );
};
export default GuardedRoute;

and in app.js use:

import RouterPage from "./pages/RouterPage";
<GuardedRoute path="/router-page" component={RouterPage} />

in Vue: at the router file use:

const guardSuccess = (to, from, next) => {
  let gUser = auth.currentUser
  if (gUser) {
    next()
  } else {
    next({ name: "Home" })
  }
}

and in the routes of the page you want to restrict access to add:

 {
    path: "/router-page",
    name: "routerPage",
    component: () => import("../views/routerPage.vue"),
    beforeEnter: guardSuccess
  }

Solution 9 - Javascript

firebase.auth().onAuthStateChanged(function(user) {
    if (user) {
   
      var user = firebase.auth().currentUser;
     
  
      if(user != null){ 
        var io=user.uid;
        window.alert("success "+io);
    
      
    
  
      }
  
    } else {
      // No user is signed in.
      Window.reload();

    }
  });

first check if user exist then get it id by

> firebase.auth().currentUser.uid

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionChrisView Question on Stackoverflow
Solution 1 - JavascriptbojeilView Answer on Stackoverflow
Solution 2 - JavascriptPrestonDocksView Answer on Stackoverflow
Solution 3 - JavascriptyueView Answer on Stackoverflow
Solution 4 - JavascriptSheldon OliveiraView Answer on Stackoverflow
Solution 5 - JavascriptKidali KevinView Answer on Stackoverflow
Solution 6 - JavascriptfunzeyeView Answer on Stackoverflow
Solution 7 - JavascriptJonathanView Answer on Stackoverflow
Solution 8 - JavascriptLuhaib-jView Answer on Stackoverflow
Solution 9 - Javascriptali remaityView Answer on Stackoverflow