How to send verification email with Firebase? - android

I am signing up my users using Firebase's email and password method. like this:
mAuth.createUserWithEmailAndPassword(email, password)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
FirebaseUser signed = task.getResult().getUser();
writeNewUser(signed.getUid());
new android.os.Handler().postDelayed(
new Runnable() {
public void run() {
updateUser(b);
}
}, 3000);
} else {
new android.os.Handler().postDelayed(
new Runnable() {
public void run() {
onSignupFailed();
}
}, 3000);
}
}
});
After the user's email has been successfully registered, I would like Firebase to send a verification email. I know this is possible using Firebase's sendEmailVerification. In addition to sending this email, I want the user's account to be disabled until they verify the email. This would also require using Firebase's isEmailVerified feature. However, I have been unsuccessful in getting Firebase to send the verification email, I have not been able to figure out to get it to disable and enable the account sending the verification email and after it has been verified.

This question is about how to use Firebase to send the verification email. The OP is unable to figure out how to disable and enable the account sending the verification email and after it has been verified.
Also, this is not properly documented in the firebase documentation. So I am writing a step by step procedure that someone may follow if he/she is facing the problem.
1) User can use createUserWithEmailAndPassword method.
Example:
mAuth.createUserWithEmailAndPassword(email, password)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
Log.d("TAG", "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()) {
// Show the message task.getException()
}
else
{
// successfully account created
// now the AuthStateListener runs the onAuthStateChanged callback
}
// ...
}
});
If the new account was created, the user is also signed in, and the AuthStateListener runs the onAuthStateChanged callback. In the callback, you can manage the work of sending the verification email to the user.
Example:
onCreate(...//
mAuthListener = new FirebaseAuth.AuthStateListener() {
#Override
public void onAuthStateChanged(#NonNull FirebaseAuth firebaseAuth) {
FirebaseUser user = firebaseAuth.getCurrentUser();
if (user != null) {
// User is signed in
// NOTE: this Activity should get onpen only when the user is not signed in, otherwise
// the user will receive another verification email.
sendVerificationEmail();
} else {
// User is signed out
}
// ...
}
};
Now the send verification email can be written like:
private void sendVerificationEmail()
{
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
user.sendEmailVerification()
.addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
// email sent
// after email is sent just logout the user and finish this activity
FirebaseAuth.getInstance().signOut();
startActivity(new Intent(SignupActivity.this, LoginActivity.class));
finish();
}
else
{
// email not sent, so display message and restart the activity or do whatever you wish to do
//restart this activity
overridePendingTransition(0, 0);
finish();
overridePendingTransition(0, 0);
startActivity(getIntent());
}
}
});
}
Now coming to LoginActivity:
Here if the user is successfully logged in then we can simply call a method where you are writing logic for checking if the email is verified or not.
Example:
mAuth.signInWithEmailAndPassword(email, password)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
//Log.d("TAG", "signInWithEmail: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", "signInWithEmail:failed", task.getException());
} else {
checkIfEmailVerified();
}
// ...
}
});
Now consider the checkIfEmailVerified method:
private void checkIfEmailVerified()
{
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
if (user.isEmailVerified())
{
// user is verified, so you can finish this activity or send user to activity which you want.
finish();
Toast.makeText(LoginActivity.this, "Successfully logged in", Toast.LENGTH_SHORT).show();
}
else
{
// email is not verified, so just prompt the message to the user and restart this activity.
// NOTE: don't forget to log out the user.
FirebaseAuth.getInstance().signOut();
//restart this activity
}
}
So here I m checking if the email is verified or not. If not, then log out the user.
So this was my approach to keeping track of things properly.

send verification to user's Email
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
user.sendEmailVerification();
check if user is verified
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
boolean emailVerified = user.isEmailVerified();

Use FirebaseAuth.getInstance().getCurrentUser().sendEmailVerification() and FirebaseAuth.getInstance().getCurrentUser().isEmailVerified()
There is no way to disable the account via the Firebase SDK. The thing you can do is use the GetTokenResult containing the Firebase Auth ID Token and validate it against your custom backend or set a flag to Firebase database corresponding to that user. Personally I'd go with the flag in the Firebase database

For sending email link with Firebase first you need to grab FirebaseAuth instance
using the instance we create user on Firebase through:
firebaseauth.createUserWithEmailAndPassword(email,pass);
When method return success we send verification link to user using Firebase user instance as follows:
final FirebaseUser user = mAuth.getCurrentUser();
user.sendEmailVerification()
See this link: https://technicalguidee.000webhostapp.com/2018/10/email-verification-through-link-using-firebase-authentication-product-android.

mAuth.createUserWithEmailAndPassword(email,password).addOnCompleteListener(new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if(task.isSuccessful()){
mAuth.getCurrentUser().sendEmailVerification().addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
Toast.makeText(this, "please check email for verification.", Toast.LENGTH_SHORT).show();
loadingBar.dismiss();
}else{
Toast.makeText(this, task.getException().getMessage() , Toast.LENGTH_SHORT).show();
}
}
});

For Kotlin
val user: FirebaseUser? = firebaseAuth.currentUser
user?.sendEmailVerification()

Related

Android Firebase can update user email once only

Currently i'm making user email and password update for my homework app.
the problem is the Email can only be update ONCE. after that it just give information such as
D/FirebaseApp: Notifying auth state listeners.
D/FirebaseApp: Notified 1 auth state listeners.
(there is no issue with updating password. only email)
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
// Get auth credentials from the user for re-authentication //User Sekarang punya email
AuthCredential credential = EmailAuthProvider.getCredential(emailCurrent, passCurrent); // Current Login Credentials \\
// 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) {
if (task.isSuccessful()) {
Toast.makeText(getApplicationContext(), "User re-authenticated.", Toast.LENGTH_SHORT).show();
//Now change your email address \\
//----------------Code for Changing Email Address----------\\
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
user.updateEmail(email).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
Toast.makeText(getApplicationContext(), "User email address updated.", Toast.LENGTH_SHORT).show();
System.out.println("Email Updated");
}
}
});
//----------------------------------------------------------\\
} // End of isSuccessful
} // End of onComplete
});
Expected can update email unlimitedly.
Currently can only update email once.

How to check whether a user is authenticated or not in Firebase?

I have a few sign-up methods in my app as shown below:
Let's revolve the problem around Google sign-in method:
What I am doing is that when a user signs in enteringDataIntoUserNode() method is called inside signInWithCredential() method like:
private void firebaseAuthWithGoogle(GoogleSignInAccount acct) {
AuthCredential credential =
GoogleAuthProvider.getCredential(acct.getIdToken(), null);
// signing in
mAuth.signInWithCredential(credential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
// entering default values in the database
enteringDataIntoUserNode();
Intent intent = new Intent(LoginAndSignupActivity.this, MainActivity.class);
startActivity(intent);
finish();
}
else {
Log.w(TAG, "signInWithCredential:failure", task.getException());
}
}
});
}
enteringDataIntoUserNode()
private void enteringDataIntoUserNode() {
final String currentUid = mAuth.getCurrentUser().getUid();
//
String deviceToken = FirebaseInstanceId.getInstance().getToken();
final String userName = mAuth.getCurrentUser().getDisplayName();
String imageUrl = mAuth.getCurrentUser().getPhotoUrl().toString();
String userStatus = "Hi there! How is it going?";
// inserting data in key-value pair
usersReference.child(currentUid).child("user_name").setValue(userName);
usersReference.child(currentUid).child("user_status").setValue(userStatus);
usersReference.child(currentUid).child("user_image").setValue(imageUrl);
usersReference.child(currentUid).child("device_token").setValue(deviceToken);
// when this last value will be inserted then, making an intent to MainActivity
usersReference.child(currentUid).child("user_thumb_image").setValue(imageUrl)
.addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if(task.isSuccessful()){
Log.d(TAG, "onComplete: Data insertion for the new user is successful ");
}
}
});
}
enteringDataIntoUserNode() method is simply passing some default data to the database every time a user signs in. But if a user change its details like image or username etc. and sign out and again sign in through Google sign in method then again enteringDataIntoUserNode() method will be called and user details would be overwritten with the default ones.
My question is that is there any way to check whether a user is signing in for the first time or not during the Google sign in so that in the latter case I can skip calling enteringDataIntoUserNode() method and prevent overwriting of data.
Same thing I want to acheive during Facebook and Phone Number sign in.
If you check if the user logs in for the first time, it's the same thing if you want to check if a user is new. So to solve this, we can simply call the isNewUser() method in the OnCompleteListener.onComplete callback like this:
OnCompleteListener<AuthResult> completeListener = new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
boolean isNewUser = task.getResult().getAdditionalUserInfo().isNewUser();
if (isNewUser) {
Log.d("TAG", "The user is new!");
} else {
Log.d("TAG", "The user is not new!");
}
}
}
};
For more informations, please see the official documentation.
You could check when the account was created with:
task.getResult().getUser().getMetadata().getCreationTimestamp()
See the reference docs.
But a common approach is also to check if the user already exists in the database using a transaction.

How Reauthenticate User at Firebase

I'm trying to update the user's email, but firebase requires a recent login for this, so I tried to use the method that was in the firebase documentation, but the problem is how I can pass the password user? I do not keep the password in db, and I can not get it from the firebase, so I do not know how I can pass the password.
The solution I thought is to ask the user to enter the password, so I tried to use a field to enter the password but it still does not work, so how can I pass the password to the firebase and reauthenticate the user to change the data?
You need to re-authenticate a user, referring to documentation.
For instance you have a field where the user types his password, let's say it`s an EditText etPassword, and you have user email in SharedPreferences
So the code to re-authenticate will look like this:
AuthCredential credential = EmailAuthProvider
.getCredential(SharedPreferences.getmail(),etPassword.getText().toString());
// 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.");
if(task.isSuccessful()){
updateUserEmail();
} else {
// Password is incorrect
}
}
});
where updateUserEmail() is
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
user.updateEmail("user#example.com")
.addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
Log.d(TAG, "User email address updated.");
}
}
});

Email not being Verified in Firebase

I am using Firebase's isEmailVerified method to verify an email. The following is the code:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_verifying);
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
mAuth=FirebaseAuth.getInstance();
spinner=(ProgressBar)findViewById(R.id.progressBar);
spinner.setVisibility(View.GONE);
Log.e("I am launched","hello");
if(user.isEmailVerified()==true){
Log.e("I am here","hello");
State state= new AccountSettingUp(this);
state.doAction();
} else {
Log.e("Maybe i am here","yes");
user.sendEmailVerification()
.addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
Log.d("email", "Email sent.");
}
}
});
}
Here, the else code should only run when the email is not verified. However, even after I verify the email and restart the activity, the if statement is not true and the email is sent again.
This behavior appears to be a limitation, possibly a bug, in the current version (10.0.1) of Firebase Authentication. The same issue is reported in this related question.
I tried doing a reload() of the user data after the email verification. That didn't help. As reported in the related question, it seems that a sign-out/sign-in is required to get the new email verification status.
For firebase-auth:10.0.1, it seems that it is not possible. However, the workaround is to log the user out and logging them in again. Upon signing in, the isEmailVerified() function will work properly.
I did a sign up activity
mAuth.createUserWithEmailAndPassword(Email, Password).addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()){
user = mAuth.getCurrentUser();
UserProfileChangeRequest profileChange = new UserProfileChangeRequest.Builder()
.setDisplayName(FirstName)
.build();
user.updateProfile(profileChange).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if(task.isSuccessful()){
Toast.makeText(getBaseContext(), "Thanks for signing up, " + FirstName + "! Please verify your email!", Toast.LENGTH_SHORT).show();
user.sendEmailVerification();
mAuth.signOut();
Intent a = new Intent(getBaseContext(),Login_Activity.class);
startActivity(a);
}
else {
Toast.makeText(getBaseContext(),"Failed to create username",Toast.LENGTH_SHORT).show();
}
}
});
}
else{
Toast.makeText(getBaseContext(),"Failed",Toast.LENGTH_SHORT).show();
}
}
});
As seen in the 'task.isSuccessful()' portion of the '.updateProfile' code, I did an 'mAuth.signOut();' and informing them to verify their email before sending them back to the login screen.
On the Login screen, I did a simple 'if (user.isEmailVerified())' statement to check for verification. If they are still not verified, a toast will appear to remind them, if they are verified then they will proceed into the next activity.
Hope this helps!

How to delete a Firebase user from Android App?

I'm trying to code a Delete User method in my Android App, but I have some issues each time I execute it. This method will be executed when a user pushes the Delete account button on an Activity. My apps works with FirebaseUI Auth.
Here is the method:
private void deleteAccount() {
Log.d(TAG, "ingreso a deleteAccount");
FirebaseAuth firebaseAuth = FirebaseAuth.getInstance();
final FirebaseUser currentUser = firebaseAuth.getCurrentUser();
currentUser.delete().addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
Log.d(TAG,"OK! Works fine!");
startActivity(new Intent(Main3WelcomeActivity.this, Main3Activity.class));
finish();
}
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.e(TAG,"Ocurrio un error durante la eliminaciĆ³n del usuario", e);
}
});
}
1) When I execute that function a Smart Lock message appears on the screen and the user is signed in again. Here is a screenshot of this message.
2) On other occasions, when the user is logged in for a long time, the function throws an Exception like this:
06-30 00:01:26.672 11152-11152/com.devpicon.android.firebasesamples E/Main3WelcomeActivity: Ocurrio un error durante la eliminaciĆ³n del usuario
com.google.firebase.FirebaseException: An internal error has occured. [ CREDENTIAL_TOO_OLD_LOGIN_AGAIN ]
at com.google.android.gms.internal.zzacq.zzbN(Unknown Source)
at com.google.android.gms.internal.zzacn$zzg.zza(Unknown Source)
at com.google.android.gms.internal.zzacy.zzbO(Unknown Source)
at com.google.android.gms.internal.zzacy$zza.onFailure(Unknown Source)
at com.google.android.gms.internal.zzact$zza.onTransact(Unknown Source)
at android.os.Binder.execTransact(Binder.java:453)
I've read that I have to re-authenticate the user but I'm not sure how to do this when I'm working with Google Sign In.
As per the Firebase documentation can user delete() method to remove user from the Firebase
Before remove the user please reAuthenticate the user.
Sample code
final 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) {
user.delete()
.addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
Log.d(TAG, "User account deleted.");
}
}
});
}
});
For more details : https://firebase.google.com/docs/auth/android/manage-users#re-authenticate_a_user
If you want to user re Authentication with other singin provider only need to change the Provider for GoogleAuthProvider below is the sample code
GoogleAuthProvider.getCredential(googleIdToken,null);
The answer provided by Ansuita Jr. is very beautifully explained and is correct with just a small problem.
The user gets deleted even without having successful re-authentication.
This is because we use
user.delete()
in the onComplete() method which is always executed.
Therefore, we need to add an if check to check whether the task is successful or not which is mentioned below
user.reauthenticate(credential)
.addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
Log.e("TAG", "onComplete: authentication complete");
user.delete()
.addOnCompleteListener (new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
Log.e("TAG", "User account deleted.");
} else {
Log.e("TAG", "User account deletion unsucessful.");
}
}
});
} else {
Toast.makeText(UserProfileActivity.this, "Authentication failed",
Toast.LENGTH_SHORT).show();
}
}
});
Your delete callback already handles the case of a failure, why do you add addOnFailureListener later?
Try to delete it, this way:
private void deleteAccount() {
Log.d(TAG, "ingreso a deleteAccount");
FirebaseAuth firebaseAuth = FirebaseAuth.getInstance();
final FirebaseUser currentUser = firebaseAuth.getCurrentUser();
currentUser.delete().addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
Log.d(TAG,"OK! Works fine!");
startActivity(new Intent(Main3WelcomeActivity.this, Main3Activity.class));
finish();
} else {
Log.w(TAG,"Something is wrong!");
}
}
});
}
First of all, you need to store the auth token or the password at the moment your user is logging in. If your app doesn't provide such as Google Sign-in, Facebook Sign-in or others, you just need to store the password.
//If there's any, delete all stored content from this user on Real Time Database.
yourDatabaseReferenceNode.removeValue();
//Getting the user instance.
final FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
if (user != null) {
//You need to get here the token you saved at logging-in time.
String token = "userSavedToken";
//You need to get here the password you saved at logging-in time.
String password = "userSavedPassword";
AuthCredential credential;
//This means you didn't have the token because user used like Facebook Sign-in method.
if (token == null) {
credential = EmailAuthProvider.getCredential(user.getEmail(), password);
} else {
//Doesn't matter if it was Facebook Sign-in or others. It will always work using GoogleAuthProvider for whatever the provider.
credential = GoogleAuthProvider.getCredential(token, null);
}
//We have to reauthenticate user because we don't know how long
//it was the sign-in. Calling reauthenticate, will update the
//user login and prevent FirebaseException (CREDENTIAL_TOO_OLD_LOGIN_AGAIN) on user.delete()
user.reauthenticate(credential)
.addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
//Calling delete to remove the user and wait for a result.
user.delete().addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
//Ok, user remove
} else {
//Handle the exception
task.getException();
}
}
});
}
});
}
#Android developers:
I faced an issue where the Firebase Auth information was persisting in the device's disk AFTER uninstalling the app. After experimenting and reading about it, I found that setting android:allowBackup="false" and android:fullBackupContent="false" in the Manifest's <application> tag will ensure the identity information is not persisted after the app is uninstalled.
Please note, this kind of persistence was not happening on all Android devices. In fact, it started happening on one of my devices that never had this issue.
If the sign-in method is "Anonymous", you can just call
FirebaseAuth.getInstance().getCurrentUser().delete().addOnCompleteListener(task -> {
if (task.isSuccessful()){
Log.d(TAG, "Deletion Success");
}
});
But if it's a different method, you will need a re-authentication.
How to re-authenticate
Use this methods :-
remove()
is equivalent to calling set(null).
or
removeUser()
removeUser(credentials, [onComplete])
Only get current user and delete it by using following method it'll work fine
user.delete();
and you can add on Oncompletelistner also
by addinduser.delete().addOnCompleteListner(new OnCompleteListner)and more on
If you are using AuthUI or FirebaseAuth you can just do the following
AuthUI.getInstance().delete(context).addOnSuccessListener {
}.addOnFailureListener{
}
OR
FirebaseAuth.getInstance().currentUser.delete().addOnSuccessListener...
If you are using FirebaseUI Auth you can just do the following
private void delete() {
FirebaseAuth firebaseAuth = FirebaseAuth.getInstance();
FirebaseUser user=firebaseAuth.getCurrentUser();
user.delete()
.addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()){
startActivity(new Intent(Main3WelcomeActivity.this, Main3Activity.class));
finish();
Toast.makeText(Main3WelcomeActivity.this,"Account deleted",Toast.LENGTH_LONG).show();
}else {
Toast.makeText(Home.this,"failed",Toast.LENGTH_LONG).show();
}
}
});}

Categories

Resources