Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

onAuthStateChanged inconsistent

When a user comes to my site, I use onAuthStateChanged to determine if the user is already signed-in from a previous session or not.

Main issue is that it has been inconsistent for a small % of users - code seems to not be detecting that they do have a valid signed-in session going on.

The following code is on the app itself, users are on that page after a redirect from the homepage or login page.

The homepage of the site also uses onAuthStateChanged to determine if the user should be redirected to the app directly. The login page uses signInWithEmailAndPassword and when the log in is successful, redirects them to the app page (which has the following code).

firebase.auth().onAuthStateChanged(function (authUser) {
  if (authUser) return initApp(authUser);

  // issue: sometimes users that *should* be signed-in get signed in anonymously here
  firebase.auth().signInAnonymously().then(function (authUser) {
    initApp(authUser);
  }
});

Is onAuthStateChanged just not something I should be using for my use case? Any idea how to improve / fix this?

Edit: This SEEMS to happen more with users on mobiles.

like image 715
Dan P. Avatar asked Sep 08 '16 15:09

Dan P.


1 Answers

I don't think you're using onAuthStateChanged as it was intended. You shouldn't think of it as a way to test if a user is signed in or not. When you call onAuthStateChanged, you're registering a function that'll be called every time an authentication state change occurs.

In my apps (typically React apps), onAuthStateChange is called exactly one time usually within the main or highest level of the app. It's called to register an authentication event handler. That event handler function then responds to changes in the authentication state. If the handler function is passed 'user' that is null, indicating that no user is authenticated, it redirects to the signin page. If the handler function is called and passed a 'user' that IS set, it typically redirects to the the app's homepage or dashboard after setting a few app-wide vars with user details.

My code that processes a user's attempt to signin calls one of Firebase's signin methods catches (and deals with) any responding errors. It does NOT use a 'then' function to respond to a successful signin. It doesn't need to. An auth state change event is triggered and my event handler function, that I registered with onAuthStateChanged, is called and deals with the redirect, etc.

If you're calling onAuthStateChanged from a number of different locations within your app, you're effectively registering a number of different handler functions that could possibly all respond to an auth state change. As bojeil commented, in your example, the function you're registering with onAuthStateChanged could call the signInAnonymously function ...which would re-trigger an auth state change. A user could never actually sign out, they'd just switch to an anonymous authentication meaning they'd always be authenticated one way or the other. Maybe that's what you want? I'm not sure what would be happening when multiple handlers are registered and are being triggered.

I guess it's also worth mentioning that the event handler function you register with onAuthStateChanged doesn't get called until after your app loads. You can't use onAuthStateChanged as a synchronous way to determine if a user is authenticated or not then determine how to continue loading your app. As a kind of workaround, my apps usually set a simple flag in local storage indicating the user is authenticated. When the app loads, after a refresh or something, it checks for that auth flag in local storage then continues to load accordingly. When the auth state change handler triggers, the app's state is either validated as correct or, if the auth state is different, the app reacts accordingly.

like image 77
MurrayR Avatar answered Nov 05 '22 02:11

MurrayR