Anonymous account on Firebase is not persistent (recreated every few hours) - android

In my android app I offer the ability for users to add content. The user signs in anonymously on Firebase and their content is linked to their anonymous UID.
Unfortunately the anonymous account on Firebase is not persistent (every few hours a user is assigned a new UID thus loosing the ability to edit their own sets).
I execute the following logic every time the MainActivity is created:
FirebaseAuth auth = FirebaseAuth.getInstance();
if(auth.getCurrentUser() == null){
Log.d("Test", "Logging in anonymously");
auth.signInAnonymously().addOnCompleteListener(new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if(task.isSuccessful()){
Log.d("Test", "Anonymous Login success");
}else{
Log.d("Test", "Anonymous Login failed");
Toast.makeText(MainActivity.this, "Error while creating anonymous account", Toast.LENGTH_LONG).show();
}
}
});
}else{
Log.d("Test", "Already Logged-In");
}
How can I achieve that the anonymous accounts is permanent per device installation?

Related

Im Creating Registration with email and Password but with Fullname in Android Studio with Firebase

Im Creating Registration with email and Password but with Fullname of the user and display it when the users Login i try to find tutorials in youtube but no one provide or i dont just find it, only email and password tutorials ,
Anyone here could help me?
This is for Android
Im using Android Studio
my backend is Firebase
I want the user in the registration
when click to the confirm button the Full name is will be registered to the firebase and display it in users profile..
thanks a lot.
By the way
the code that I am using now is this
progressBar.setVisibility(View.VISIBLE);
//create user
auth.createUserWithEmailAndPassword(email, password)
.addOnCompleteListener(SignupActivity.this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
Toast.makeText(SignupActivity.this, "createUserWithEmail:onComplete:" + task.isSuccessful(), Toast.LENGTH_SHORT).show();
progressBar.setVisibility(View.GONE);
// If sign in fails, display a message to the user. If sign in succeeds
// the auth state listener will be notified and logic to handle the
// signed in user can be handled in the listener.
if (!task.isSuccessful()) {
Toast.makeText(SignupActivity.this, "Authentication failed." + task.getException(),
Toast.LENGTH_SHORT).show();
} else {
startActivity(new Intent(SignupActivity.this, MainActivity.class));
finish();
}
}
});
As you said you found tutorials with email and password.
Follow those tutorials, the only thing extra you have to do is, make full name edit text in XML and during sign up check if it is not null and make users DB in the realtime database using UID.
if (!emailAdd.equals("") || !pass.equals("") || (!name.eqauls(""){
mAuth.createUserWithEmailAndPassword(emailAdd, pass)
.addOnCompleteListener(new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
// Getting UID of Current User
FirebaseUser current_user = mAuth.getCurrentUser();
String UID = current_user.getUid();
usersDB.child(UID).child("email").setValue(emailAdd);
usersDB.child(UID).child("name").setValue(name);
Toast.makeText(youractivity.this, "Registeration done", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(youractivity.this, "Registeration Failed", Toast.LENGTH_SHORT).show();
}
}
});
}

How to handle FirebaseAuthUserCollisionException

I started getting a FirebaseAuthUserCollisionException exception when I try to sign in with Facebook in my Android application.
com.google.firebase.auth.FirebaseAuthUserCollisionException: An
account already exists with the same email address but different
sign-in credentials. Sign in using a provider associated with this
email address.
I am using Firebase to handle the registration and Facebook to deliver a "one-click" login method, using a com.facebook.login.widget.LoginButton view as a trigger.
These sign-in method was already working. I was able to register a account with Facebook, and use the same method to log-in this account. But now have start to throwing this exception.
Here is the code where I register a account from Facebook and proceed with login:
private void handleFacebookAccessToken(AccessToken token) {
final ProgressDialog dialog = new ProgressDialog(this);
dialog.show(getString(R.string.dialog_wait));
firebaseAuth.signInWithCredential(FacebookAuthProvider.getCredential(token.getToken()))
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#SuppressWarnings("ThrowableResultOfMethodCallIgnored")
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
dialog.close();
registerNewUserFromSocialLogin(firebaseAuth.getCurrentUser());
} else {
if(task.getException() instanceof FirebaseAuthUserCollisionException) {
//TODO: handle sign-in with different credentials
} else {
dialog.close();
LoginManager.getInstance().logOut();
Toast.makeText(LoginActivity.this,
R.string.error_login,
Toast.LENGTH_SHORT).show();
}
}
}
});
}
And my Gradle file with current use library:
compile 'com.google.firebase:firebase-auth:10.2.1'
compile 'com.facebook.android:facebook-android-sdk:[4,5)'
So my problem is: I don't know how to handle FirebaseAuthUserCollisionException exception.
None of the solutions in StackOverflow or Firebase Documentation help me. I am looking for a solution that is able to login the user although the duplicated credential, to stil deliver the "one-click" login method.
You will get that error when the user had previously signed in with the same email using a different provider. For example, the user signs in with email user#gmail.com using Google. The user then tries to sign in with the same email but using Facebook. The Firebase Auth backend will return that error (account exists with different credential). In that case, you should use the fetchProvidersForEmail to look up the existing providers associated with email user#gmail.com, in this case google.com. You signInWithCredential to the existing google account to prove ownership of that account, and then linkWithCredential the Facebook credential the user originally was trying to sign in with. This merges both accounts so in the future the user can sign in with either.
This happens when you use the single accounts per email. If you want to allow different accounts per email, you can switch to multiple accounts per email in the Firebase console.
Here is an example:
mAuth.signInWithCredential(authCredential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
// Account exists with different credential. Assume the developer wants to
// continue and link new credential to existing account.
if (!task.isSuccessful() &&
task.getException() instanceof FirebaseAuthUserCollisionException) {
FirebaseAuthUserCollisionException exception =
(FirebaseAuthUserCollisionException)task.getException();
if (exception.getErrorCode() ==
ERROR_ACCOUNT_EXISTS_WITH_DIFFERENT_CREDENTIAL) {
// Lookup existing account’s provider ID.
mAuth.fetchProvidersForEmail(existingAcctEmail)
.addOnCompleteListener(new OnCompleteListener<ProviderQueryResult> {
#Override
public void onComplete(#NonNull Task<ProviderQueryResult> task) {
if (task.isSuccessful()) {
if (task.getResult().getProviders().contains(
EmailAuthProvider.PROVIDER_ID)) {
// Password account already exists with the same email.
// Ask user to provide password associated with that account.
...
// Sign in with email and the provided password.
// If this was a Google account, call signInWithCredential instead.
mAuth.signInWithEmailAndPassword(existingAcctEmail, password)
addOnCompleteListener(new OnCompleteListener<AuthResult> {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
// Link initial credential to existing account.
mAuth.getCurrentUser().linkWithCredential(authCredential);
}
}
});
}
}
}
});
}
}
});
There is no need for this, you can just allow multiple accounts merge under firebaase->authentication-> sign in method -> Advanced - > change (multiple accounts per email address.
Firebase will merge the same email address but will give you different user UID.
See sample below.
AuthCredential authCredential = FacebookAuthProvider.getCredential(token.getToken());
mAuth.signInWithCredential(authCredential)
.addOnCompleteListener(this, task -> {
if (task.isSuccessful()) {
// Sign in success, update UI with the signed-in user's information
Log.d(TAG, "signInWithCredential:success");
FirebaseUser user = mAuth.getCurrentUser();
LoginFacebookGoogleActivity.this.updateUI(user);
} else {
// If sign in fails, display a message to the user.
Log.w(TAG, "signInWithCredential:failure", task.getException());
if(task.getException() instanceof FirebaseAuthUserCollisionException){
FirebaseAuthUserCollisionException exception = (FirebaseAuthUserCollisionException) task.getException();
//log this bundle into the analytics to analyze which details you want to collect
}
Toast.makeText(LoginFacebookGoogleActivity.this, "Authentication failed " + task.getException(), Toast.LENGTH_SHORT).show();
LoginFacebookGoogleActivity.this.updateUI(null);
}
});

Anonymous authentication flow for Android application?

I am trying to implement anonymous authentication and then google authentication for data sayc.
Here is the code for anonymous auth
mAuthListener = new FirebaseAuth.AuthStateListener() {
#Override
public void onAuthStateChanged(#NonNull FirebaseAuth firebaseAuth) {
user = firebaseAuth.getCurrentUser();
if (user != null) {
// User is signed in
userNameText.setText(user.getDisplayName());
Picasso.with(MainActivity.this).load(user.getPhotoUrl()).into(profileImageView);
Log.d(TAG, "onAuthStateChanged: " + user.getDisplayName());
} else {
// User is signed out
Log.d(TAG, "onAuthStateChanged: user is null");
mAuth.signInAnonymously()
.addOnCompleteListener(MainActivity.this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
Log.d(TAG, "signInAnonymously:onComplete:" + task.isSuccessful());
// If sign in fails, display a message to the user. If sign in succeeds
// the auth state listener will be notified and logic to handle the
// signed in user can be handled in the listener.
if (!task.isSuccessful()) {
Log.d(TAG, "signInAnonymously", task.getException());
Toast.makeText(MainActivity.this, "Authentication failed.",
Toast.LENGTH_SHORT).show();
}
// ...
}
});
}
}
};
and then user can opt for sign in using Google account
AuthCredential credential = GoogleAuthProvider.getCredential(acct.getIdToken(), null);
mAuth.getCurrentUser().linkWithCredential(credential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
Log.d(TAG, "linkWithCredential:onComplete:" + task.isSuccessful());
// If sign in fails, display a message to the user. If sign in succeeds
// the auth state listener will be notified and logic to handle the
// signed in user can be handled in the listener.
if (!task.isSuccessful()) {
task.getException().printStackTrace();
Toast.makeText(MainActivity.this, "Authentication failed.",
Toast.LENGTH_SHORT).show();
}
}
});
this runs as expected. But I am not getting user.getDisplayName even after app restart. In firebase console it shows user linked to anonymous account.
And also when same user re-installs app a new anonymous user is created, but this time when user selects same google account as previous, it does not link to already existing user in console. Pleas help.
Your issue was recently addressed on firebase-talk (I found it with a seach for "firebase anonymous authentication app reinstall").
Anonymous authentication accounts don't persist across app uninstalls. When an app is uninstalled, everything it has saved locally will be deleted, including the anonymous auth token that identifies that account. There is no easy way to reclaim that token for the end user. Instead, you should encourage your end users to fully log in with a supported account provider so that they can log in from all their devices without worry of losing their data.

Firebase Auth - with Email and Password - Check user already registered

I want to check when a user attempts to signup with createUserWithEmailAndPassword() in Firebase user Authentication method, this user is already registered with my app.
To detect whether a user with that email address already exists, you can detect when the call to createUserWithEmailAndPassword () fails with auth/email-already-in-use. I see that #Srinivasan just posted an answer for this.
Alternatively, you can detect that an email address is already used by calling fetchSignInMethodsForEmail().
The usual flow for this is that you first ask the user to enter their email address, then call fetchSignInMethodsForEmail, and then move them to a screen that either asks for the rest of their registration details (if they're new), or show them the provider(s) with which they're signed up already.
When the user trying to create an user with same email address, the task response will be "Response: The email address is already in use by another account."
mFirebaseAuth.createUserWithEmailAndPassword(email,password)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if(task.isSuccessful()){
//User registered successfully
}else{
Log.i("Response","Failed to create user:"+task.getException().getMessage());
}
}
});
First of all, you need to make sure you have that restriction enabled in Firebase console (Account and email address settings). Take a look at #Srinivasan's answer.
Then, do this in your java code:
firebaseAuthenticator.createUserWithEmailAndPassword(email, password)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (!task.isSuccessful()) {
if (task.getException() instanceof FirebaseAuthUserCollisionException) {
Toast.makeText(SignUpActivity.this, "User with this email already exist.", Toast.LENGTH_SHORT).show();
}
} else {
sendVerificationEmail();
startActivity(new Intent(SignUpActivity.this, DetailsCaptureActivity.class));
}
// ...
}
});
This is where the trick happens:
if (task.getException() instanceof FirebaseAuthUserCollisionException) {
Toast.makeText(SignUpActivity.this,
"User with this email already exist.", Toast.LENGTH_SHORT).show();
Several exceptions can be thrown when registering a user with email and password, but the one we are interested in is the FirebaseAuthUserCollisionException. As the name implies, this exception is thrown if the email already exists. If the exception thrown is an instance of this class, let the user know.
As a practice of #Frank's answer here is the code of using fetchProvidersForEmail()
private boolean checkAccountEmailExistInFirebase(String email) {
FirebaseAuth mAuth = FirebaseAuth.getInstance();
final boolean[] b = new boolean[1];
mAuth.fetchProvidersForEmail(email).addOnCompleteListener(new OnCompleteListener<ProviderQueryResult>() {
#Override
public void onComplete(#NonNull Task<ProviderQueryResult> task) {
b[0] = !task.getResult().getProviders().isEmpty();
}
});
return b[0];
}
I was looking into this kind of condition where we can detect if user exists or not and perform registration and login. fetchProvidersForEmail is best option right now. I have found this tutorial. Hope it helps you too!
See : Manage Users
UserRecord userRecord = FirebaseAuth.getInstance().getUserByEmail(email);
System.out.println("Successfully fetched user data: " + userRecord.getEmail());
This method returns a UserRecord object for the user corresponding to the email provided.
If the provided email does not belong to an existing user or the user cannot be fetched for any other reason, the Admin SDK throws an error. For a full list of error codes, including descriptions and resolution steps, see Admin Authentication API Errors.
private ProgressDialog progressDialog;
progressDialog.setMessage("Registering, please Wait...");
progressDialog.show();
mAuth.createUserWithEmailAndPassword(email, password)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
//checking if success
if (task.isSuccessful()) {
//Registration was successfull:
Toast.makeText(RegistrationActivity.this, "Successfully registered!", Toast.LENGTH_LONG).show();
} else {
//Registration failed:
//task.getException().getMessage() makes the magic
Toast.makeText(RegistrationActivity.this, "Registration failed! " + "\n" + task.getException().getMessage(), Toast.LENGTH_LONG).show();
}
progressDialog.dismiss();
}
});
Add below code to MainActivity.java file.When user attempt to register with the same email address a message "The email address is already used by another account" will pop up as a Toast
mAuth.createUserWithEmailAndPassword(email,password).addOnCompleteListener(new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if(!task.isSuccessful()){
Toast.makeText(MainActivity.this, task.getException().getMessage(), Toast.LENGTH_SHORT).show();
}
if(task.isSuccessful()){
Toast.makeText(MainActivity.this, "Sign up successfull", Toast.LENGTH_SHORT).show();
}
}
});
You do not have to do anything because the backend of Firebase will do the job.
Unless you are referring to reauthenticating of the app.
Take a scenario for an example, w

Firebase - Email Verification Mail Not Working - An internal error has occurred. [ USER_NOT_FOUND ]

I am trying to send a verification email after successful registration of user. Which gives me the error An internal error has occurred. [ USER_NOT_FOUND ]. This is the code I have at present -
public void signUpUser(View view){
EditText mailEditText = (EditText) findViewById(R.id.editText);
EditText pwdEditTet = (EditText) findViewById(R.id.editText2);
String email = mailEditText.getText().toString();
String password = pwdEditTet.getText().toString();
Log.d("Info",email);
Log.d("Info",password);
mAuth.createUserWithEmailAndPassword(email,password).addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
try {
AuthResult result = task.getResult();
Log.d("Sign up", "createUserWithEmail:onComplete:" + task.isSuccessful());
// If sign in fails, display a message to the user. If sign in succeeds
// the auth state listener will be notified and logic to handle the
// signed in user can be handled in the listener.
if (!task.isSuccessful()) {
Toast.makeText(MainActivity.this, R.string.auth_failed,
Toast.LENGTH_SHORT).show();
}else{
Log.d("Sign up", "Sending verification email");
// Sending the verification email
//FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
mAuth.getCurrentUser().sendEmailVerification()
.addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
Log.d("Email Sent", "Verification Email sent.");
}else{
Log.d("Email Sent",task.getException().getLocalizedMessage());
}
}
});
}
} catch (Exception e){
Toast.makeText(MainActivity.this,R.string.user_exist,Toast.LENGTH_SHORT).show();
Log.e("Exception",e.getLocalizedMessage());
}
}
});
}
and here is the log which is getting printed -
10-11 10:10:50.372 31518-31518/au.com.savedme D/Sign up: Sending verification email
10-11 10:10:51.438 31518-31518/au.com.savedme D/Email Sent: An internal error has occurred. [ USER_NOT_FOUND ]
10-11 10:11:00.429 31518-31538/au.com.savedme W/DynamiteModule: Local module descriptor class for com.google.firebase.auth not found.
Please have a look and let me know in case I am doing anything wrong here.
I also had the same issue, and the reason i found behind this is, if you are trying this code with same user which you have already created and then deleted it from firebase console, it will not work.
Try with new email address which you have not tried a single time, and it will work.
Note that createUserWithEmailAndPassword() not only creates the user,
but also, if successful, signs the user in. When the creation and
sign-in occurs when there is an existing signed-in user, there appears
to be a Firebase bug related to signing out and clearing the cache for
the previous user.
I was able to make your code work for a previously signed-in and later
deleted user by calling signOut() before
createUserWithEmailAndPassword().
reference
I am having the same problem. What I found out is that, mAuth.getCurrentUser().sendEmailVerification() is not working inside mAuth.createUserWithEmailAndPassword(email,password) method.
I wrote the code outside the createUserWithEmailAndPassword(email,password) method and bang I received the verification email. Strange.
FirebaseUser user= FirebaseAuth.getInstance().getCurrentUser();
if(user!=null){
user.sendEmailVerification().addOnCompleteListener(MainActivity.this,new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if(task.isSuccessful()){
Log.i("Success","Yes");
}
else {
Log.i("Success","No"+task.getException());
}
}
});
}
Are you sure you have enabled Email/Password authentication in console? If not, you can go to https://console.firebase.google.com and click on your project, click 'Auth', then 'SIGN-IN METHOD', click on pen icon to enable it. Hope this helps!

Categories

Resources