How to handle the firebase authentication session to have the user signed in indefinitely

9,442 views
Skip to first unread message

MAW

unread,
Jul 29, 2020, 11:30:33 AM7/29/20
to Firebase Google Group
I have been using firebase for 6 months now and I didn't pay attention to keeping the user logged in indefinitely till now, and everything was going fine. The token expires after 1 hour and the onAuthStateChanged() gets fired with a user=null. This is where I set the logic to sign the user out and navigate to the login page.

Now I'm developping a PWA, where it will be installed on mobile devices (added to the home screen), and the users must be signed in all the time.

I have been reading through the documentation and the firebase group here, and I got that using signInWithCustomToken() should solve the issue, but again, the custom token is still expiring after 1 hour and the onAuthStateChanged() gets fired again with user=null. And hence the user gets logged out with a redirection to the login page.

I have a firebase function that generates the custom token and sends it to the front-end, then the front-end uses this token to signInWithCustomToken(), hoping it will keep the session up, but still happening only for 1 hour!

This doesn't happen on the computer, when using the browser and the browser is set to always continue from where the user left!
It only happens on the mobile devices, where the PWA is installed (added to the home screen)

I got from all what I read that the user session doesn't expire, but the token does! These are my questions
  1. If the user session is never expiring, until an explicit sign out, why does the onAuthStateChanged() fires with a user=null?!
  2. In this case how to handle the sign in logic, and the onAuthStateChanged() properly, so the user session stays alive in the PWA, and the application stays working in the background?!!
Any help, example would be very much appreciated.

Thanks in advance.

Kato Richardson

unread,
Jul 29, 2020, 1:50:56 PM7/29/20
to Firebase Google Group
Hello MAW,

Firebase manages auth state on your behalf and it doesn't expire after 1 hour. You shouldn't need to do anything here to keep your users logged in. If auth state is expiring, then something else is likely going wrong.

Behind the scenes, Auth works as follows:
  • Sign in with your preferred provider (email/pass, oauth, custom tokens, et al)
  • Exchange that token for a Firebase Auth ID token
  • Behind the scenes, Firebase also mints a refresh token
  • At the end of an hour, the Auth ID token expires, but is automatically renewed as needed by using the refresh token
The Auth ID token and refresh token are stored in the devices local storage. Clearing that cache would of course cause the user to be logged out.

☼, Kato

--
You received this message because you are subscribed to the Google Groups "Firebase Google Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to firebase-tal...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/firebase-talk/832c7dcf-114e-48d0-b605-2ffed45eb074o%40googlegroups.com.


--

Kato Richardson | Developer Programs Eng | kato...@google.com | 775-235-8398

MAW

unread,
Jul 29, 2020, 4:51:15 PM7/29/20
to Firebase Google Group
Thanks Kato.

This is what the documentaion says, but I have a different experience.

It maybe, as you mentioned, something I'm doing. But I'm just following the documentation and logic, and still can not get it to work. let me explain how I'm doing it and tell me what is wrong.

Here is what I'm doing

Approach #1
  1. During the sign in phase, set the firebase auth persistence to local to make sure it's gonna persist the session
    • firebase.auth().setPersistence(firebase.auth.Auth.Persistence.LOCAL)
  2. Then I'm using the sign in with email and password
    • firebase.auth().signInWithEmailAndPassword(...)
  3. Then register the event listener for the auth state change.
    • If user is not null, proceed with the normal after sign in logic.
    • If user is null, redirect to sign in page.
Approach #2, as the documentation, and the discussions here states that a signInWithCustomToken() would solve the issue
  1. Same as Approach #1 - Step #1
  2. Same as Approach #1 - Step #2
  3. Use a firebase function to generate a new Custom Token and send it to the front-end.
  4. The front-end uses signInWithCustomToken() to sign in again with the custom token.
  5. Same as Approach #1 - Step #3

Neither of the works (to keep the user signed in) as the issue is the following:

The issue is, after 1 hour of the login time, both tokens expire, and the firebase.auth().onAuthStateChanged() gets fired again with a null user, which triggers the logic that directs the user to the sign in page.

The issue is that the firebase.auth().onAuthStateChanged() is being fired with a state indicating that the user is no longer signed in. And this is happening because firebase tried to communicate with the Auth componenet with an expired token. 

From what you mentioned, "At the end of an hour, the Auth ID token expires, but is automatically renewed as needed by using the refresh token", if firebase takes care of this and refreshes the token automatically, why does the auth state change with a null user?!! where it sould have just replaced the token with the newly minted one and the user stays logged in. and we continue to have the user object available!

Also, in the discussions here, it has been mentioned that the token expires but the user stays signed in. If this is true, why would the auth state change to null user?!!

Approach #1 login logic sample

firebase.auth().setPersistence(firebase.auth.Auth.Persistence.LOCAL)
.then(() => {
return firebase.auth().signInWithEmailAndPassword(email, password)
.then(
async data => {
if (data.user.emailVerified) {
// Continue with the successful login logic ...
}
// ***********************************************
})
})


Approach #2 login logic sample

firebase.auth().setPersistence(firebase.auth.Auth.Persistence.LOCAL)
.then(() => {
return firebase.auth().signInWithEmailAndPassword(email, password)
.then(
async data => {
if (data.user.emailVerified) {
let getCustomToken = firebase.functions().httpsCallable("<GenerateCustomToken_Function_Name>")
let customToken = await getCustomToken()
firebase.auth().signInWithCustomToken(customToken)
.catch(function (error) {
// Handle error
});
// Continue with the successful login logic ...
})

})


Common auth state change event listener

firebase.auth().onAuthStateChanged(async user => {
if (user) {
if (user.emailVerified) {
// Handle user signed in state, and redirect to the user home page
} else {
// Sign the user out
// Handle user signed out state, and redirect to log in page
}
} else {
// Handle user signed out state, and redirect to log in page
// *** This is where the issue happens (after 1 hour, this else block gets executed)!!! ***
}
})



On Wednesday, July 29, 2020 at 1:50:56 PM UTC-4, Kato Richardson wrote:
Hello MAW,

Firebase manages auth state on your behalf and it doesn't expire after 1 hour. You shouldn't need to do anything here to keep your users logged in. If auth state is expiring, then something else is likely going wrong.

Behind the scenes, Auth works as follows:
  • Sign in with your preferred provider (email/pass, oauth, custom tokens, et al)
  • Exchange that token for a Firebase Auth ID token
  • Behind the scenes, Firebase also mints a refresh token
  • At the end of an hour, the Auth ID token expires, but is automatically renewed as needed by using the refresh token
The Auth ID token and refresh token are stored in the devices local storage. Clearing that cache would of course cause the user to be logged out.

☼, Kato

On Wed, Jul 29, 2020 at 8:30 AM MAW <m.abo...@gmail.com> wrote:
I have been using firebase for 6 months now and I didn't pay attention to keeping the user logged in indefinitely till now, and everything was going fine. The token expires after 1 hour and the onAuthStateChanged() gets fired with a user=null. This is where I set the logic to sign the user out and navigate to the login page.

Now I'm developping a PWA, where it will be installed on mobile devices (added to the home screen), and the users must be signed in all the time.

I have been reading through the documentation and the firebase group here, and I got that using signInWithCustomToken() should solve the issue, but again, the custom token is still expiring after 1 hour and the onAuthStateChanged() gets fired again with user=null. And hence the user gets logged out with a redirection to the login page.

I have a firebase function that generates the custom token and sends it to the front-end, then the front-end uses this token to signInWithCustomToken(), hoping it will keep the session up, but still happening only for 1 hour!

This doesn't happen on the computer, when using the browser and the browser is set to always continue from where the user left!
It only happens on the mobile devices, where the PWA is installed (added to the home screen)

I got from all what I read that the user session doesn't expire, but the token does! These are my questions
  1. If the user session is never expiring, until an explicit sign out, why does the onAuthStateChanged() fires with a user=null?!
  2. In this case how to handle the sign in logic, and the onAuthStateChanged() properly, so the user session stays alive in the PWA, and the application stays working in the background?!!
Any help, example would be very much appreciated.

Thanks in advance.

--
You received this message because you are subscribed to the Google Groups "Firebase Google Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to fireba...@googlegroups.com.

Kato Richardson

unread,
Jul 29, 2020, 5:18:24 PM7/29/20
to Firebase Google Group
You don't need to setPersistence to LOCAL; that's already the default. There's no need to call firebase.auth().signInWithEmailAndPassword(...) during each app init. This calls signOut() first (causing onAuthStateChanged to report a null) and then reauthenticates the user. Instead, you should use onAuthStateChanged() to see if the user is already authenticated.


To unsubscribe from this group and stop receiving emails from it, send an email to firebase-tal...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/firebase-talk/84218fc5-99fa-4ebb-af96-3bc1c05a4a24o%40googlegroups.com.

MAW

unread,
Jul 29, 2020, 8:46:21 PM7/29/20
to Firebase Google Group
Sorry if I was not clear. I was trying to explain the initial login sequence, but it was not accurate.

So, the app init sequence starts as you mentioned with the onAuthStateChanged(), then it decides wheither to navigate to the user home (if user is not null), or navigate to login page if user is null. And initially, as the user is null, this is how it gets to the login page for the first time. Then, the onAuthStateChanged() takes care of the routing properly for the next hour.

Then the issue occures, after 1 hour from the initial login, the onAuthStateChanged() fires with a null user, and hence the application will direct the user to the login page.


On Wednesday, July 29, 2020 at 5:18:24 PM UTC-4, Kato Richardson wrote:
You don't need to setPersistence to LOCAL; that's already the default. There's no need to call firebase.auth().signInWithEmailAndPassword(...) during each app init. This calls signOut() first (causing onAuthStateChanged to report a null) and then reauthenticates the user. Instead, you should use onAuthStateChanged() to see if the user is already authenticated.


MAW

unread,
Jul 29, 2020, 8:46:33 PM7/29/20
to Firebase Google Group
And also to make this more clear, this only happens when the PWA is being added to the mobile home screen (downloaded on the mobile device).
It doesn't hapen when using the normal browser on a computer. On a computer using the browser, the session stays open until an explicit signout!


On Wednesday, July 29, 2020 at 5:18:24 PM UTC-4, Kato Richardson wrote:
You don't need to setPersistence to LOCAL; that's already the default. There's no need to call firebase.auth().signInWithEmailAndPassword(...) during each app init. This calls signOut() first (causing onAuthStateChanged to report a null) and then reauthenticates the user. Instead, you should use onAuthStateChanged() to see if the user is already authenticated.


MAW

unread,
Aug 4, 2020, 6:38:52 PM8/4/20
to Firebase Google Group
*** RESOLVED ***
It turened out to be a GCP API configuration issue.
The Token Service API must not be restricted, to allow the token to be refreshed.
Reply all
Reply to author
Forward
0 new messages