Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Users get logged out and remain in invalid authentication state #3885

Closed
SteveBurkert opened this issue Jul 10, 2022 · 11 comments
Closed

Users get logged out and remain in invalid authentication state #3885

SteveBurkert opened this issue Jul 10, 2022 · 11 comments
Labels

Comments

@SteveBurkert
Copy link

SteveBurkert commented Jul 10, 2022

[READ] Step 1: Are you in the right place?

We use FirebaseAuthentication, which is part of the sdk, so I think yes.

[REQUIRED] Step 2: Describe your environment

  • Android Studio version: Android Studio Chipmunk | 2021.2.1 Patch 1 Build #AI-212.5712.43.2112.8609683
  • Firebase Component: Authentication
  • Component version: 21.0.1 with bom 29.1.0

Updated dependencies in the affected releases:

com.google.android.gms:play-services-auth:20.1.0 -> com.google.android.gms:play-services-auth:20.2.0
com.android.tools.build:gradle:7.0.4 -> com.android.tools.build:gradle:7.1.3
com.google.firebase:firebase-bom:29.1.0 -> com.google.firebase:firebase-bom:29.3.1

[REQUIRED] Step 3: Describe the problem

TL;DR:
Users loose their registration and end up in an invalid anonymous registered state.
FirebaseAuth.getCurrentUser probably returns null, even though there is a user and
auth is initialized. FirebaseUser.isAnonymous returns false, even though the account is
only registered using anon registration.

Long:

It's really not easy to describe the problem, so I'll try to explain the timeline and setup.

We use Firebase for authentication and it's realtime database to build a community
feature within our application, where users have profiles.
On first app start, users get signed in anonymously, until they decide to use a real auth provider,
after which the anon and "real" account get linked. So far, so normal.

After a new release we noticed within our internal test flavor, that some of the registred (non anon) users
loose their names and profiles and can no longer interact with the community.
We also noticed thousands of database permission excpetions and almost the same amount
of FirebaseNetworkExceptions.

I investigated a company owned device that was affected and it actually turns out
that the affected "user" belongs to an anonymous regsitration (UID -> console),
although the owner of the phone was registered in our community through google since 1.5 years before that.

The only option to go back from a google/facebook etc registration to an anonymous registration,
is through logging out!
And if you log out, we sign you back in anonymously, but we will not make DB calls anymore,
since FirebaseUser.isAnonymous returns true in this case.

But in our case here, the client "thinks" that it still has a profile and is normally registered (google/facebook etc.).
Therefore the client always tries to read and write DB notes, which are restricted for anon users
and which we code-wise prohibit by calling the FirebaseAuthentication typicall methods.

Till today, we have almost like 10k affected users.

Steps to reproduce:

The only way I see that a normal registered user is "again anonymous", (and which I was
kind of able to reproduce), would be if FirebaseAuth.getCurrentUser returns null,
even though there is a normal registered account.
In this case we would wrongly call signInAnonymously OVER the current registration.

I tried it, and if you do this, the FirebaseUser will end up in an invalid state and return FALSE for
FirebaseUser.isAnonymous, even though getProviderData will only return 1 entry containing "firebase".
This would in our case result in executing multiple DB-write approaches, which will of course fail
and might be the reason for the thousands Database Permission Erros.

I don't know how FirebaseAuth.getCurrentUser would return null for normal account though.
Maybe the thousands occurences of FirebaseNetworkException are related to FirebaseAuth
returning null for current user.

I will provide a minimal repo, to reproduce the isAnonymous == false issue.
And I will provide a small code snippet of our authentication app startup.

Our authentication app startup procedure is very simple.

  1. Initialize Firebase auth state
  2. Check for a user
    2a. If there is non, register an anonymous account
    2b. If there is one, make a quick DB call, but only if the account is not anonymous

Relevant Code:

    // Called at app startup once
    private void initializeFirebaseAuth() {
        FirebaseAuth.getInstance().addAuthStateListener(new FirebaseAuth.AuthStateListener() {
            @Override
            public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) {
                firebaseAuth.removeAuthStateListener(this);
                FirebaseUser user = firebaseAuth.getCurrentUser();
                if (user != null) {
                    writeToDb(user);
                } else {
                    signInAnonymously(user);
                }
            }
        });
    }

    private void writeToDb(FirebaseUser user){
        if(user.isAnonymous){
            Timber.w("Some warning");
        }else{
            //FirebaseDatabase.someCall ...
        }
   }

    private void signInAnonymously(FirebaseUser user) {
        if(user != null){
            Timber.w("Some warning");
            return;
        }
        firebaseAuth.signInAnonymously().addOnCompleteListener(task -> {
            if (task.isSuccessful()) {
                Timber.d("Nice");
            }
        });
    }
}

Exceptions:

FirebaseNetworkException - first occurence May 5h, 2644 non-fatal events affecting 1074 users in the last 90 days

Non-fatal Exception: com.google.firebase.FirebaseNetworkException: A network error (such as timeout, interrupted connection or unreachable host) has occurred.
       at com.google.android.gms.internal.firebase-auth-api.zzti.zza(com.google.firebase:firebase-auth@@21.0.3:17)
       at com.google.android.gms.internal.firebase-auth-api.zzuc.zza(com.google.firebase:firebase-auth@@21.0.3:1)
       at com.google.android.gms.internal.firebase-auth-api.zzud.run(com.google.firebase:firebase-auth@@21.0.3:3)
       at android.os.Handler.handleCallback(Handler.java:938)
       at android.os.Handler.dispatchMessage(Handler.java:99)
       at android.os.Looper.loop(Looper.java:255)
       at android.app.ActivityThread.main(ActivityThread.java:8194)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:632)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1049)

image

Which is probably causing:

DatabaseException - first occurence May 8h, 79531 non-fatal events affecting 21038 users in the last 90 days

Non-fatal Exception: com.google.firebase.database.DatabaseException: Firebase Database error: Permission denied
       at com.google.firebase.database.DatabaseError.toException(DatabaseError.java:230)
       at com.google.firebase.database.core.utilities.Utilities$1.onComplete(Utilities.java:253)
       at com.google.firebase.database.core.Repo$7.run(Repo.java:435)
       at android.os.Handler.handleCallback(Handler.java:938)
       at android.os.Handler.dispatchMessage(Handler.java:99)
       at android.os.Looper.loopOnce(Looper.java:233)
       at android.os.Looper.loop(Looper.java:344)
       at android.app.ActivityThread.main(ActivityThread.java:8204)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:589)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1071)

image

Minimal repo - showcase isAnonymous wrong state

https://github.com/SteveBurkert/firbease-zombie-user-example

(The repo only showcases how you can reproduce to make FirebaseUser.isAnonymous return false, even though it is anonymously registered.)

Thanks in advance.

@google-oss-bot
Copy link
Contributor

I couldn't figure out how to label this issue, so I've labeled it for a human to triage. Hang tight.

@argzdev
Copy link
Contributor

argzdev commented Jul 12, 2022

Thanks for the detailed explanation and reproducible example, @SteveBurkert. I'll notify our engineers and see what we can do here.

@argzdev argzdev added the type: bug Something isn't working label Jul 12, 2022
@lisajian
Copy link

Hi, thanks for filing this issue! We are unable to promise any timeline for this, but if others also have this issue, adding a +1 on this issue can help us prioritize adding this to the roadmap.

(Googler-only internal tracking bug: b/238776633)

@svenjacobs
Copy link

svenjacobs commented Jul 22, 2022

We recently noticed a similar behaviour. Maybe it's related so I'm going to explain our findings:

First of all, we're using Anonymous Authentication in our app. We call signInAnonymously() during app start and use the (anonymous) user ID as a reference to user data in various Firestore collections and documents.

A few weeks ago users started complaining that they are losing their data on every app start. We looked into this and could reproduce a case where signInAnonymously() would return a new user on every call. Of course no app data was deleted between the executions. The app was just terminated and started again. Obviously with a new user ID, references to previously stored data in Firestore are lost which goes along with the user reportings. However when we manually cleared the app data and started the app, this faulty behaviour was gone and we received the same user ID on every app start. This is also confirmed by our affected users.

We assume that some update of the firebase-auth dependency introduced this erroneous state which can only be fixed by clearing application data.

Additionally we noticed a few FirebaseNetworkExceptions in Crashlytics coming from firebase-auth which could be the reason for this problem? In accordance with OP's findings it seems that most of these exceptions started to occur with version 21.0.3 of firebase-auth (no guarantees though as we can only look back up to 90 days in Crashlytics). These exceptions still occur with the current version 21.0.6. Some exemplary exception below:

Caused by com.google.firebase.FirebaseNetworkException: A network error (such as timeout, interrupted connection or unreachable host) has occurred.
       at com.google.android.gms.internal.firebase-auth-api.zztu.zza(com.google.firebase:firebase-auth@@21.0.6:17)
       at com.google.android.gms.internal.firebase-auth-api.zzus.zza(zzus.java:9)
       at com.google.android.gms.internal.firebase-auth-api.zzut.zzl(com.google.firebase:firebase-auth@@21.0.6:1)
       at com.google.android.gms.internal.firebase-auth-api.zzuq.zzh(com.google.firebase:firebase-auth@@21.0.6:25)
       at com.google.android.gms.internal.firebase-auth-api.zzts.zzh(zzts.java:1)
       at com.google.android.gms.internal.firebase-auth-api.zzqq.zza(zzqq.java:2)
       at com.google.android.gms.internal.firebase-auth-api.zzvb.zza(zzvb.java:16)
       at com.google.android.gms.internal.firebase-auth-api.zzuh.zzf(com.google.firebase:firebase-auth@@21.0.6:4)
       at com.google.android.gms.internal.firebase-auth-api.zzrx.zzp(zzrx.java:4)
       at com.google.android.gms.internal.firebase-auth-api.zztt.zzj(zztt.java:5)
       at com.google.android.gms.internal.firebase-auth-api.zzsh.zzc(com.google.firebase:firebase-auth@@21.0.6:1)
       at com.google.android.gms.internal.firebase-auth-api.zzsh.zzc$bridge(com.google.firebase:firebase-auth@@21.0.6:35)
       at com.google.android.gms.internal.firebase-auth-api.zzuu.run(com.google.firebase:firebase-auth@@21.0.6:1)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
       at java.lang.Thread.run(Thread.java:920)

We hope this information helps in identifying and fixing the problem soon 🤞🏼

@SteveBurkert
Copy link
Author

SteveBurkert commented Feb 27, 2023

Hey there. Any updates on this issue?

We recently added some massive logging on our end and we've found that on some permission denials,
related to the database rules, we got users with weird provider data, that seem to have the above described problem.

Here is one of the logs from crashlytics with a dedicated custom exception:

This list shows all the providers the user is signed up with...

Firebase SDK has illegal auth state. Is not anonymous user by SDK, but only has anon provider id. User: 'User.providers = [firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, firebase, fireb<truncated: 1267558 chars>

May I highlight <truncated: 1267558 chars> here!
Each provider takes up 10 characters in space (including the comma and one whitespace).
This means, that this user is roughly signed up 130 thousand times(!) with anon provider.
What the...

SDK internally isAnonymous is checked also by size of the provider info array. If it's > 1 it will directly return false.
Which is the case here. But how can this type of provider mess happen?

The provider id firebase comes from https://firebase.google.com/docs/reference/android/com/google/firebase/auth/FirebaseAuthProvider#PROVIDER_ID
right?
And FirebaseAuthProvider is only anonymous sign ups, right?
So how can we end up with 20+ anonymous providers for one user?
We have like thousand of users, having this issue.
@lisajian

@svenjacobs
Copy link

Hello, I would also like to ask what the progress is on this issue? We're still seeing a lot of FirebaseNetworkException in firebase-auth, actually it's the number one crash of our app constantly occurring, but I doubt that all affected users have a bad network connection when this happens.

Caused by com.google.firebase.FirebaseNetworkException: A network error (such as timeout, interrupted connection or unreachable host) has occurred.
       at com.google.android.gms.internal.firebase-auth-api.zzxc.zza(com.google.firebase:firebase-auth@@21.1.0:19)
       at com.google.android.gms.internal.firebase-auth-api.zzya.zza(zzya.java:9)
       at com.google.android.gms.internal.firebase-auth-api.zzyb.zzl(com.google.firebase:firebase-auth@@21.1.0:1)
       at com.google.android.gms.internal.firebase-auth-api.zzxy.zzh(com.google.firebase:firebase-auth@@21.1.0:25)
       at com.google.android.gms.internal.firebase-auth-api.zzxa.zzh(zzxa.java:1)
       at com.google.android.gms.internal.firebase-auth-api.zzty.zza(zzty.java:2)
       at com.google.android.gms.internal.firebase-auth-api.zzyj.zza(zzyj.java:16)
       at com.google.android.gms.internal.firebase-auth-api.zzxp.zzf(com.google.firebase:firebase-auth@@21.1.0:4)
       at com.google.android.gms.internal.firebase-auth-api.zzvf.zzp(zzvf.java:4)
       at com.google.android.gms.internal.firebase-auth-api.zzxb.zzj(zzxb.java:5)
       at com.google.android.gms.internal.firebase-auth-api.zzvp.zzc(com.google.firebase:firebase-auth@@21.1.0:1)
       at com.google.android.gms.internal.firebase-auth-api.zzyc.run(com.google.firebase:firebase-auth@@21.1.0:1)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1137)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:637)
       at java.lang.Thread.run(Thread.java:1012)

@argzdev
Copy link
Contributor

argzdev commented May 3, 2023

Hi all, this issue is now fixed in Firebase BoM version 32.0.0 or Authentication version 22.0.0. That said, I'll close this issue now. Feel free to reply back here if there's any issue. Thanks!

@argzdev argzdev closed this as completed May 3, 2023
@svenjacobs
Copy link

@argzdev Wow, that are great news, thank you! 👍🏼 What was the reason for the wrong authentication state and what was the fix? I'm curious and would like to know 😃

@argzdev
Copy link
Contributor

argzdev commented May 4, 2023

Hi @svenjacobs, according to the internal bug link, it seems that this is the possible reason:

This issue is because if we already have a user instance and get a new one to update, we only update the provider list, we do not change the uid.

@SteveBurkert
Copy link
Author

SteveBurkert commented May 4, 2023

That are really great news! May I ask, does this solve both of the problems, meantioned in the discussion?
And are affected user accounts "self healing"?

  1. "FirebaseUser.isAnonymous returns false, even though the account is only registered using anon registration."
  2. Duplicated entries in provider list: "...user is roughly signed up 130 thousand times(!) with anon provider." (Users get logged out and remain in invalid authentication state #3885 (comment))

Thank you, @argzdev

@argzdev
Copy link
Contributor

argzdev commented May 8, 2023

Hi @SteveBurkert, the fix is only for the first issue.

"FirebaseUser.isAnonymous returns false, even though the account is only registered using anon registration."

As for the second issue with 130 providers duplicated, this is not yet fixed. We aren't exactly sure what causes the duplicate providers, we're still trying to figure this out, so we can't guarantee that the fix for the first issue also affects the second issue.

@firebase firebase locked and limited conversation to collaborators Jun 3, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

6 participants