'Firebase javascript auth user displaying null even though user is signed in

I followed the Firebase docs for web development and I used the user.updateProfile method to add a display name to the user's profile. After signing in, I used console.log(user) and it worked but when I call updateProfile(), the value of user is null. Any solutions?

Here is the relevant code:

var button = document.getElementById("profile-button");
var username = document.getElementById("username-Box").value;

var user = firebase.auth().currentUser;

auth.onAuthStateChanged(user =>{
    console.log(user);
})


function updateProfile(){
    if (user != null){
        user.updateProfile({
        displayName : username
    }).then(user => {
        console.log("Updated Successfully");
        window.location.href="chatpage.html";
    }).catch(err =>{
        console.log(err);
        window.alert(err);
    });
    }else if(user == null){
        console.log("No user signed in");
    }
}


Solution 1:[1]

You need to wait for onAuthStateChanged to fire before assigning the user variable, otherwise the Auth object may be in an intermediate state. This is documented:

By using an observer, you ensure that the Auth object isn't in an intermediate state—such as initialization—when you get the current user. When you use signInWithRedirect, the onAuthStateChanged observer waits until getRedirectResult resolves before triggering.

You can also get the currently signed-in user by using the currentUser property. If a user isn't signed in, currentUser is null:

It's worth explicitly pointing out that the user variable you console.log in onAuthStateChanged is not the same user variable that's used in your updateProfile method. While the user maybe "logged in" when onAuthStateChanged fires, they are likely not logged in when you set your outer user variable. Therein lies your problem.

It's not clear from your code where updateProfile is called, but Peter Haddad's answer is likely the solution I would implement. However, note that with the code snippet supplied in that answer you'll also need to change your updateProfile method to accept a user parameter. Another approach would be to assign the user variable inside of onAuthStateChanged.

let user;

auth.onAuthStateChanged(u => user = u);

With that approach your updateProfile method should work as is. Just keep in mind that you may have a race condition depending on when you call updateProfile.

Solution 2:[2]

Since console.log(user) is returning the correct user, then inside the authstatechanged call the updateProfile:

auth.onAuthStateChanged(user =>{
    console.log(user);
    updateProfile(user);
})

Solution 3:[3]

Based on your snippet, I am assuming that updateProfile() is your onClick/onSubmit event handler for clicking your "update profile" button.

Because of this, your user is likely to have logged in by the time they press the button and therefore it is safe to use firebase.auth().currentUser in your event handler rather than maintain a user object in the global scope.

var eleButton = document.getElementById("profile-button");
var eleUsername = document.getElementById("username-Box");

function updateProfile() {
  let user = firebase.auth().currentUser;

  if (!user) {
    alert('Please log in before clicking update profile!')
    return;
  }

  // get current value of '#username-Box'
  let username = eleUsername.value.trim();

  if (!username) {
    alert('Please enter a valid username!')
    return;
  }

  user.updateProfile({
    displayName : username
  }).then(user => {
    console.log("Updated Successfully");
    window.location.href="chatpage.html";
  }).catch(err =>{
    console.log(err);
    window.alert(err);
  });
}

In your original code, you had the following:

var user = firebase.auth().currentUser; // <-- global-scope variable

auth.onAuthStateChanged(user =>{ // <-- function-scope variable
    console.log(user);
})

When onAuthStateChanged fires, it does log the value of user, but it sets and logs it's own version of user, not the user variable in the global-scope.

If you wanted to update the global-scope version, you need to rename the variable used in your onAuthStateChanged handler so that it doesn't shadow the user global-scope variable.

var user = firebase.auth().currentUser; // <-- global-scope variable

auth.onAuthStateChanged(_user =>{ // <-- function-scope variable
    user = _user;
    console.log(user);
})

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Peter Haddad
Solution 3 samthecodingman