I have a DispatchActivity as my Launcher Activity, which is meant to check if there is a user currently signed in. If the user is signed in, I send them to their ProfileActivity. Otherwise, I send them to a LogInActivity. Here is my code in DispatchActivity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dispatch);
//.....................
auth = FirebaseAuth.getInstance();
authListener = new FirebaseAuth.AuthStateListener() {
#Override
public void onAuthStateChanged(FirebaseAuth firebaseAuth) {
FirebaseUser user = firebaseAuth.getCurrentUser();
if (user != null) {
launchProfileActivity();
} else {
// User is signed out
launchLoginActivity();
}
}
};
}
#Override
public void onStart() {
super.onStart();
auth.addAuthStateListener(authListener);
}
#Override
public void onStop() {
super.onStop();
if (authListener != null) {
auth.removeAuthStateListener(authListener);
}
}
No matter what I do, firebaseAuth.getCurrentUser(), never returns null on my primary testing device. According to the Docs, getCurrentUser() will be null unless there is a User Currently Signed in. When I Log some of this User's details, they are consistent with a "Test" user I created previously, (i.e. calling user.getEmail() returns "email#example.com".
This is problematic, as I most certainly don't have any users in my Console's User Database (In Authentication/Users). I deleted this test User from the database some time ago, and the database is empty.
I tried running the App on another device, and it executed properly. However, performing a fresh install on my primary testing device does not fix the problem.
Question:
As far as I can see, the issue is related to some kind of persistent user state with my device; since running a different device works fine. Since I haven't deliberately configured this to occur, I would like to know what is causing this inconsistency between my Auth User Database and the Device.
If the Database is empty, where is auth.getCurrentUser() getting this previously deleted user object from?
Thank you.
Firebase Authentication will cache an authentication token for the user when they're signed in. This prevents having to authenticate every little interaction the user makes with other services provided by Firebase. This token gets automatically refreshed periodically, but until then, the SDK assumes that the token represents the user. You'll find that the token will expire after some time, or you can force the issue by uninstalling and reinstalling the app, or clearing its data.
Authentication works regardless of the contents of your Realtime Database. They are independent from each other, except where security rules limit access to the currently authenticated user.
In Your Manifest File Add The Following
In the <manifest> tag (at the end)
xmlns:tools="http://schemas.android.com/tools"
Then in the <application> tag (at the begining)
tools:replace="android:allowBackup"
android:allowBackup="false"
android:fullBackupContent="false"
just as #Doug Stevenson mentioned above firebase saves some data on the phone adding these tags will ensure that that does not happen... so when you uninstall the app and install it again it will clear all the data associated with the app.
I had the same exact question and could not find the answer to this problem anywhere. I tried everything. I don't know why this works but I restarted my phone and it happened to fix everything. Super late but hope it helps for anyone else with the same problem.
Related
I'm not going to paste any code because I receive the desired behavior when a user creates account with a phone number in firebase auth.
My problem is after an app update, firebaseUser.getCurrentUser is null despite the fact that the user is already signed up.
My question:
How do I mimic a behavior like WhatsApp which doesn't require the user to always go through OTP after every app update?
Iv tried using authState:
auth.addAuthStateListener(firebaseAuth -> {
user = firebaseAuth.getCurrentUser();
if(user == null)
signUp() });
Hoping after update user won't be null. But it's always null after updating the app.
Actually what I didn't realize is that I was trying to mimic an update behavior by installing and uninstalling the app. Turns out token credentials are lost in the process. I just assumed Firebase attaches to the device identity some how, some where. I admit I need some instruction
My app is not automatically logging in when I restart the Android emulator. I believe previously it was doing so - though this might have been a bug caused by some bad code I have since ironed out. So to troubleshoot this problem I first need to discover whether or not this is simply a feature of the emulator.
Here is my code. I've confirmed that it successfully logs into FirebaseAuth and creates a user. According to documentation, automatically logging in on reboot should be as easy as this:
#Override
public void onStart() {
super.onStart();
//Get Firebase auth instance
auth = FirebaseAuth.getInstance();
// Check if user is signed in (non-null)
firebaseUser = auth.getCurrentUser();
}
The emulator has no bearing on the way Firebase Auth actually works. The problem is almost certainly that you're asking the SDK if the user is signed in before the SDK is certain about that. Instead of calling auth.getCurrentUser() you should use an auth state listener to get a callback when the final authentication state of the user is known. It might not be known immediately at launch, as the user's token might have expired and need to be refreshed at the server. This takes time.
Your app should wait until this auth state listener indicates that the user is actually signed. This means that your listener will actually be the thing to move your UI along to do things like make queries and present data to the user.
This is what I've come up with to handle auth in my Android app backed by anonymous authentication.
public class StartupActivity extends AppCompatActivity {
FirebaseAuth.AuthStateListener mAuthListener;
#Override
protected void onStart() {
super.onStart();
FirebaseAuth.getInstance().addAuthStateListener(mAuthListener = firebaseAuth -> {
if (firebaseAuth.getCurrentUser() != null) {
LoggedInActivity.newInstance(this);
} else {
IntroActivity.newInstance(this);
}
});
}
#Override
protected void onStop() {
FirebaseAuth.getInstance().removeAuthStateListener(mAuthListener);
super.onStop();
}
}
This StartupActivity is the one defined in my AndroidManifest.xml to be my app's main launcher Activity.
The pattern works well: at the end of IntroActivity, my code authenticates the user anonymously and sends them to the LoggedInActivity. Every launch after, the anonymous authentication persists through and the user goes straight to LoggedInActivity.
However, some users report losing their anonymous authentication and effectively losing their data since my other inner-app screens are driven off Firebase nodes that correspond to the user's UID.
This is pretty bad, but it only happens to a few users it seems. And only for anonymous auth - if it happened for email auth, it wouldn't even be a big deal, since users could log back in. But for anonymous, it's a pretty big issue. The user loses everything.
The issue could be tied to either Firebase SDK updates or app updates - that's when it seems to happen most / be reported most by my users.
Why is this happening? Is this a bad pattern for auth? I love the concept of using anonymous authentication to allow users to simply use your app without login, and I believe this is Firebase's intention as well. It's almost like I need to give them the option of backing their account with an actual login though, since this bug has such bad effects.
I believe I was able to reproduce this issue myself.
After getting an angry mail from a user, I tested what would happen if I updated the app (raising the version code for good measure) and tried to open it while my device was offline. Turns out Firebase logs me out, as I believe it might consider the internal copy of the Database outdated and wipes it completely, so it's basically the equivalent of a reinstall with no credentials. This doesn't happen after updating and opening the app while online.
This would explain why this only happens to a very small percentage of users, as they need to be Anonymous users who update the app and then try to open it with no internet connection in their devices, which I don't think would happen often.
The system was designed so that a user can start out in anonymous mode, in order to keep signup friction low. But you can write code to convert an anonymous account to a permanent account. This is what you should do for users who would like to retain their privileges if they're willing to provide some sign-in credentials.
Anonynmous auth credentials can be lost if you sign them out, or the user clears the app storage, or the user uninstalls the app.
I've recently discovered that Firebase Auth saves itself on the device even after my app is uninstalled. I can't figure out how to REMOVE this old Auth info.
I don't want a user to still be signed in after uninstalling and reinstalling the app. If for no other reason than my own testing of what I expect to be "clean installs" on the same device.
I understand there is no easy way to capture an uninstall event, so I want to clear out any potential old Auth info on the first launch.
So I added code (which seems to work fine) to check if this is the first launch:
Boolean firstRun = prefs.getBoolean("firstrun", true);
if (firstRun) {
// delete everything an old user could have left behind
// ==> This is where I need help <==
prefs.edit().putBoolean("firstrun", false).apply();
} else {
// move along, not the first launch
}
I've tried (unsuccessfully):
FirebaseAuth authData = FirebaseAuth.getInstance();
authData.signOut();
These calls also seem to be the advice in this related question for iOS, but I haven't been able to apply its wisdom:
Firebase - Deleting and reinstalling app does not un-authenticate a user
Even after calling signOut() the app keeps logging me in under the old account!
My "logout" button uses FirebaseAuth.getInstance().signOut(); and works. Is there something odd (possessed?) about this "old" Auth instance that is being saved after an uninstall that it just won't die?
Specifically when I uninstall and then install/run from Android Studio:
at first authData and currentUser both are not null
I call the above code, trying to get rid of this old user
3 millisecond later (immediately after I call that
code) they are still NOT NULL.
Another 2 milliseconds, currentUser IS NULL (yay?)
Another 71 milliseconds... still null (so far so good)
Just under a second later... I'M SIGNED IN AS THE OLD USER?! How is this possible?
In the Firebase Console under Authentication, this account is shown as last signed in 6 days ago. So it's not somehow getting re-signed-in.
Does anyone know how to remove FirebaseAuth data from a device? I don't want to "delete" the user account, just remove all traces of it from this device.
Oddly enough, the account I keep getting unwillfully logged in under isn't even the last account that logged into my app on this device. And this was never a problem in the past (hence my not even knowing that Firebase saved Auth after uninstall). So it looks like Auth info isn't always saved after uninstall... but when it happens it's impossible to remove?
Any help much appreciated!
Add android:allowBackup="false" in your <application> in manifest:
From the docs:
android:allowBackup
Whether to allow the application to participate in the backup and restore infrastructure. If this attribute is set to false, no backup or restore of the application will ever be performed, even by a full-system backup that would otherwise cause all application data to be saved via adb. The default value of this attribute is true.
Try also FirebaseAuth.getInstance().getCurrentUser().delete
Firebase stores auth info in shared preference with file names starting with "com.google.firebase.auth.api.". Therefor if you delete these files as part of your log off flow it would help the purpose.
public void clearFirebaseAuthInfo(Context ctx)
{
File dir = new File(ctx.getFilesDir().getParent() + "/shared_prefs/");
String[] children = dir.list();
for (int i = 0; i < children.length; i++)
{
if(children[i].contains("com.google.firebase.auth.api."))
{
new File(dir, children[i]).delete();
}
}
}
The Firebase Auth doc's recommended way to get the current user is:
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
if (user != null) {
// User is signed in
} else {
// No user is signed in
}
So I went ahead and did exactly that at the very beginning of my first activity:
override fun onCreate(savedInstanceState: Bundle?) {
Log.d(TAG, "⟳ onCreate")
super.onCreate(savedInstanceState)
if (FirebaseAuth.getInstance().currentUser == null) {
Log.d(TAG, "User is null. Sending user to log in.")
val intent = Intent(this, FacebookLoginActivity::class.java)
startActivity(intent)
finish()
} else {
Log.d(TAG, "User has been found. Launching MainActivity")
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)
finish()
}
}
But this is when strange things start happening 😱
Steps:
I killed the app from memory
Deleted all its data & cache
Uninstall & install again then launch
Actual: FirebaseAuth.getInstance().currentUser was NOT null! Okay guessing the Firebase library is trying to do something smart and figure out my previous log in history, but:
The uid it returns is not my user Id. I cannot use this as I already keep data for the user in my DB with an other legit uid previously returned for this user.
I can NOT find this uid on
https://console.firebase.google.com/u/0/project/.../authentication/users How is this possible?
This uid has been popping up at various times causing me errors, and it is always this same rogue uid.
A couple of things I checked:
FirebaseAuth.getInstance().currentUser.providerData
shows that this uid is associated with my Facebook account, so I
must have logged in with it before. (I call FacebookAuthProvider.getCredential(...) in the next activity) But my real legit uid should also be associated with my Facebook account which is the one I am interested in.
FirebaseAuth.getInstance().currentUser.isAnonymous returns false, so
the problem is probably not related anonymous login
How do I clear this "phantom" rogue user id from the system?
How do I check for this? I don't want to call FacebookAuthProvider.getCredential(...) every time the user opens the app.
(Using 'firebase-auth:12.0.1')
If you have a user that is apart of your app and you if you decide to delete its account from the Firebase Console, you need to know that if the same returns to use your app again, another uid is generated, which is obvious that is different from the first one. So this user, even if it has the same details (userName, emailAddress and so on) before it was deleted, is treated as a new user, with a new uid.
I got the same issue as you. I am using flutter with Android device.
This is what I tried:
Clear the cache for the app.
Delete the app.
Restart the phone.
Reinstall the app.
Then, FirebaseAuth.getInstance().getCurrentUser() will no longer hold the value.
For example in my app, I use firestore, it will throw permission error when accessing firestore resource because of invalid userId (it dependes on the security rules). You can make your app defensive to ask user to login again. Or you can do firebaseUser.reload() it will throw userId invalid exception.
The actually reason why FirebaseAuth.getInstance().getCurrentUser() will hold the value before reboot still unknown.