FirebaseAuthInvalidCredentialsException when using "One account per email address" - android

... if you don't allow multiple accounts with the same email
address, a user cannot create a new account that signs in using a
Google Account with the email address ex#gmail.com if there already is
an account that signs in using the email address ex#gmail.com and a
password.
I was able to sign in with Google provider for the same email that was already registered via Email provider, so Google provider replaced Email provider and latter then fails to sign in with FirebaseAuthInvalidCredentialsException: The password is invalid or the user does not have a password..
Steps to reproduce:
Sign up with Email provider
-> Sign out
-> Sign in with Google provider
-> Sign out
Basically it should not allow to replace one provider with another and throw FirebaseAuthUserCollisionException: The email address is already in use by another account.
Some code that I use for sign in/sign out:
public void signUpEmail(String email, String password) {
mFirebaseAuth.createUserWithEmailAndPassword(email, password)
.addOnCompleteListener(this, task -> {
if (!task.isSuccessful()) {
Log.e("signUpWithEmail", task.getException());
}
});
}
private void firebaseAuthWithGoogle(GoogleSignInAccount acct) {
AuthCredential credential = GoogleAuthProvider.getCredential(acct.getIdToken(), null);
mFirebaseAuth.signInWithCredential(credential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override public void onComplete(#NonNull Task<AuthResult> task) {
if (!task.isSuccessful()) {
Log.e("signInWithCredential", task.getException());
}
}
});
}
public void signInEmail(String email, String password) {
mFirebaseAuth.signInWithEmailAndPassword(email, password)
.addOnCompleteListener(this, task -> {
if (!task.isSuccessful()) {
Log.e("signInWithEmail", task.getException());
}
});
}
public void signOut() {
Auth.GoogleSignInApi.signOut(mGoogleApiClient);
mFirebaseAuth.signOut();
startSignInActivity();
}
Thank you!

To optimize the login UI steps and enhance account security, Firebase Authentication has a concept of 'trusted provider', where the identity provider is also the email service provider. For example, Google is the trusted provider for #gmail.com addresses, Yahoo is the trusted provider for #yahoo.com addresses, and Microsoft for #outlook.com addresses.
In the "One Account per Email address" mode, Firebase Authentication tries to link account based on email address. If a user logins from trusted provider, the user immediately signs into the account since we know the user owns the email address.
If there is an existing account with the same email address but created with other credentials (e.g. password or non-trusted provider), the previous credentials are removed for security reasons.
A phisher (who is not the email address owner) might create the initial account - removing the initial credential would prevent the phisher from accessing the account afterwards. The legit user can set up a password by going through the password reset flow, where she would need to prove she owns the email address.

Multiple accounts per email address will create a new user with a different uid for different providers using the same email.
To recreate:
Sign in with google email x#x
Sign in with facebook email x#x
Create email password account x#x
Now you'll get 3 different users.
If you use the strongly recommended single accounts per email, the 3 providers above would be within the same user (one uid).
When you first create the google account x#x and try to sign in with new facebook account with email x#x, you will get an error that linking is required to proceed. You will then have to sign in the first google user and link the new facebook user to it.

Related

FirebaseAuth - Let user change password using any provider - Android

I have a social media app, I'm using FirebaseUI to let users sign in/up to the app,using Email, Google or Facebook.
How can I let user to change his/her password later if using "Email" as a
provider?
If using Facebook or Google as providers can I let him/her set Email-Password as Authentication Method by giving him/her an option to change password?.
The change password action from user should set Email-Password as Authentication Method in firebase with a new password input from the user.
Then, The user should be able to login using Email-Password or the Authentication Provider( Facebook/Google) linked with same email.
Answering your question:
Yes.
Here is a sample code snippet for changing/updating the user password:
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
String newPassword = "SOME-SECURE-PASSWORD";
user.updatePassword(newPassword)
.addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
Log.d(TAG, "User password updated.");
}
}
});
Details of using Firebase User is available here.
2.
a. Changing the password in your app:
NO
The SignIn Providers such as Facebook, Google and Twitter do not open this features (API) to prevent middleman and other attacks/abuses.
b. User changed the password in the service provider after signed-in
The user is still able to login to your app, authentication process is deal directly to the service provider, so you don't have to worry!
c. Multiple authentication with the same email address.
Referring to
let's say user A logged in using Facebook to my app, then he went to his profile in MY APP , and changed his password, next time to login I want him to have 2 options: 1- Login using Facebook normally 2- Login using his facebook Email + the password that he saved earlier
The answer is YES, but you have to merge the details first, here is the reference. You can actually link/merge the user details of the same email address by identifying the same Firebase user ID regardless of the authentication provider they used to sign in.
For example, a user who signed in with a password can link a Google account and sign in with either method in the future. Or, an anonymous user can link a Facebook account and then, later, sign in with Facebook to continue using your app.
Hope it helps!

Firebase phone authentication : once phone entered check if there is a user with that phone in users

Hello every one i am trying to make phone authentication for the login and using signup with email and password when the user is signed up it stores email and password in the firebase default users and also add new firebase object with additional user information Phone , Car information , Name
now for the login the user enters their phone but (but) i don't want just any user who isn't signed up before to login and get authenticated i want to check if there is a user phone number as entered exists in the database
i cant use the UID because the user is not logged in yet what to do ?
Osama, during sign up, you need to authenticate the user using phone (+xxxxxxxxxx).
The next immediate step you need is to link this phone with the email and password.
So let's say the user has sign out now. And he wants to sign in again.
1) e.g. he's in the phone number view, and he keys in his phone number (+xxxxxxxxxx), after he keys in the sms code correctly, you need to check if this phone is link to any other email password credentials
In the FIRAuth auth signInWithCredential using phone, you can check the FIRAdditionalUserInfo for "phone" and "password" to know if it's already linked to a password and prompt him to login.
2) e.g. he chooses to sign in (it should only ask for his email and password)
Updates:
private void signInWithPhoneAuthCredential(PhoneAuthCredential credential) {
mAuth.signInWithCredential(credential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
// Sign in success, update UI with the signed-in user's information
Log.d(TAG, "signInWithCredential:success");
FirebaseUser user = task.getResult().getUser();
// ...get the user.providerData and FIRAdditionalUserInfo providerID "password"
} else {
// Sign in failed, display a message and update the UI
Log.w(TAG, "signInWithCredential:failure", task.getException());
if (task.getException() instanceof FirebaseAuthInvalidCredentialsException) {
// The verification code entered was invalid
}
}
}
});
}

Is it possible to detect FirebaseAuthUserCollisionException when use FirebaseAuth?

I has some problem when I try to create new account[email, password]in my app using FirebaseAuth. I want to detect if email is already use in other account. For example, I want to create account a#b.c in my app, but I'm already using this email to login by facebook. So, Is it possible to detect FirebaseAuthUserCollisionException in Firebase.
This is my code.
mAuth.createUserWithEmailAndPassword(edt1.getText().toString(), edt2.getText().toString())
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
// Sign in success, update UI with the signed-in user's information
Log.d(TAG, "createUserWithEmail:success");
FirebaseUser user = mAuth.getCurrentUser();
startActivity( new Intent( NewRegisterForEmali.this, NewLoginActivity.class));
finish();
}else if(task.getException().equals("com.google.firebase.auth.FirebaseAuthUserCollisionException")){
Log.d(TAG, "Collision!");
} else {
// If sign in fails, display a message to the user.
Log.w(TAG, "createUserWithEmail:failure", task.getException());
Toast.makeText(NewRegisterForEmali.this, "Authentication failed.",
Toast.LENGTH_SHORT).show();
task.getException();
}
// ...
}
});
Logcat:
com.google.firebase.auth.FirebaseAuthUserCollisionException: The email address is already in use by another account.
at com.google.android.gms.internal.zzeaw.zzaw(Unknown Source)
at com.google.android.gms.internal.zzdzu.zza(Unknown Source)
at com.google.android.gms.internal.zzebh.zzax(Unknown Source)
at com.google.android.gms.internal.zzebk.onFailure(Unknown Source)
at com.google.android.gms.internal.zzeay.onTransact(Unknown Source)
at android.os.Binder.execTransact(Binder.java:565)
maybe this link will help
Dealing with Email address already in use - Firebase Authentication
answer by #alex mamo
The first one is to verify if the email address exists and than display a message. This is exactly what you said. The message is up to you.
The second approach is to enable users to have multiple accounts per email address. With other words, if a user signs up with gmail and then signs up with Facebook and he has the same email address, than he ends up having 2 different accounts. A single email address, 2 different accounts This is not a good practice but according to your needs, you can even use it.
The third approach is to have only one account per email address. This means that you are preventing the users from creating multiple accounts using the same email address with different authentication providers. This a common practice and also the default rule in the Firebase console. This means, that you'll want to implement later another kind of authentication with another provider, it will follow the same rule. In this case, will have a single email address with a single account.
To enable or disable this option, go to your Firebase console, choose Authentication, select the SIGN-IN METHOD tab and at the bottom of your page you'll find the Advanced section.
Hope it helps.

Android FirebaseUI Auth - How to reauthenticate?

Related Question: How does Firebase Auth UI deal with reauthentication?
(This question is for iOS, and is unsolved)
I would like to allow a user to update their email/password/etc with FirebaseUI on Android.
According to the guide, the "drop-in" UI provides:
Account Management - flows to handle account management tasks, such as account creation and password resets.
On GitHub, it looks like the AuthUI Management Page feature is still in progress (right?)
So, I've created my own account management page, but some of the actions are security sensitive and require reauthentication:
Some security-sensitive actions—such as deleting an account, setting a primary email address, and changing a password—require that the user has recently signed in. If you perform one of these actions, and the user signed in too long ago, the action fails and throws FirebaseAuthRecentLoginRequiredException.
The example code requires that we retrieve the credentials from the user before passing it to the reauthenticate:
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
// Get auth credentials from the user for re-authentication. The example below shows
// email and password credentials but there are multiple possible providers,
// such as GoogleAuthProvider or FacebookAuthProvider.
AuthCredential credential = EmailAuthProvider
.getCredential("user#example.com", "password1234");
// Prompt the user to re-provide their sign-in credentials
user.reauthenticate(credential)
.addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
Log.d(TAG, "User re-authenticated.");
}
});
However, getting the credentials from the user is non-trivial, since I allow sign in with Google, email, facebook, and phone number. For example, signing in with a phone number requires that a text be sent to the phone. This needs more than just an alert dialog asking for a password.
On Github, there was a merge for adding a reauthentication builder a few months ago, but I've been unable to find this function in the most recent FirebaseUI version. Something like AuthUI.createReauthIntentBuilder() would be perfect.
What is the best approach for re-authenticating a user with Firebase on Android? Can I use the AuthUI.createSignInIntent(), or is implementing my own reauthentication dialog really the only way?
Currently using: FirebaseUI Auth 3.1.2
mUser.updateEmail(cek_email).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()){
Toast.makeText(getActivity(), "succes", Toast.LENGTH_SHORT).show();
}
}
});
use method updateEmail

Android firebase authentication for all app users using single email ID

I have an app which accesses Firebase database and storage using email based Authentication. Is it possible to use single email ID/passwd for all the users using my app? The email ID and password are harcoded in the method shown below which is called from onCreate. This works fine while testing with one device. I have seen authentication issues although not consistent while trying from different Android devices on different API versions. I just wanted to rule out if there is any limitation in using single email ID/passwd for accessing the app/database from different devices?
mAuth.signInWithEmailAndPassword("email ID", "password")
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
System.out.println("AUTH signInWithEmail:onComplete:" + task.isSuccessful());
if (!task.isSuccessful()) {
System.out.println("AUTH signInWithEmail:failed" + task.getException());
}
}
});
Instead of hard-coding the user-id/password. I recommend you the Firebase Anonymous Account. In future, when you add support for other Auth providers like Gmail, Facebook, Twitter,. etc; You would be able to link their anonymous account with sign-in credentials.
It's super easy to convert an anonymous account to a permanent account
Refer more details about Anonymous account below,
https://firebase.google.com/docs/auth/android/anonymous-auth
You can use Firebase Authentication to create and use temporary
anonymous accounts to authenticate with Firebase. These temporary
anonymous accounts can be used to allow users who haven't yet signed
up to your app to to work with data protected by security rules. If an
anonymous user decides to sign up to your app, you can link their
sign-in credentials to the anonymous account so that they can continue
to work with their protected data in future sessions.
mAuth.signInAnonymously()
.addOnCompleteListener(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.w(TAG, "signInAnonymously", task.getException());
Toast.makeText(AnonymousAuthActivity.this, "Authentication failed.",
Toast.LENGTH_SHORT).show();
}
// ...
}
});
Hope that helps!

Categories

Resources