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!
Related
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.
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
I want my user who logged In first using FB to be able to log out and log in again using his/her google (same email).
What should I do? I read this https://firebase.google.com/docs/auth/android/account-linking ,but I don't quite understand. I thought the linking is to link accounts, regardless of the email.
While what I'm thinking is firebase identify user by email, so if I successfully log in and out from FB or Google by using same email, then firebase should know its the same user.
in the account-linking docs above, says that we need to get the credential/tokenID and call linkwithcredential , like this :
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()) {
Toast.makeText(AnonymousAuthActivity.this, "Authentication failed.",
Toast.LENGTH_SHORT).show();
}
// ...
}
});
my questions are:
where I call this ? do I need to call it every login ?
then do I also need to get the credential for every provider each time I login ?
I have checked the documentation however, I do not understand where the link is to connect the accounts. I have a Google login working and a Password/Email version working seperately, however they do not yet work together on the same account. For example I want to allow a user to log into his account with his google account or his username and password - both using the same credential token. I am using firebase as the backend.
I was hoping someone knew of a good example i could follow or if someone knew the code i needed to make the connection and where to place it on a standard log in application on Android, Many thanks !!
I think the official documentation you're looking for is under the heading "Link Multiple Auth Providers".
All you need to do is the following:
AuthCredential credential = GoogleAuthProvider.getCredential(googleIdToken, null);
mAuth.getCurrentUser().linkWithCredential(credential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
task.isSuccessful());
if (!task.isSuccessful()) {
Toast.makeText(AnonymousAuthActivity.this, "Authentication failed.",
Toast.LENGTH_SHORT).show();
}
}
});
... 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.