Verified user with Firebase - android

I want to create a login where the user only has to put his/her mail address and verify it via email. Using firebase I have this code so far:
When the user clicks the button to login after putting the mail in the field. I try to create a new account (password is random as I don't need it). If it doesn't exists I send a verification mail. If the account exists I check with checkIfVerifiedUser if the user verified the account by clicking the mail or not.
firebaseAuth.createUserWithEmailAndPassword(email, Math.random() + "").addOnCompleteListener(new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
FirebaseUser user = firebaseAuth.getCurrentUser();
user.sendEmailVerification().addOnCompleteListener((Activity) context, new OnCompleteListener() {
#Override
public void onComplete(#NonNull Task task) {
if (task.isSuccessful()) {
Toast.makeText(context, "we sent a mail, please verify", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(context, "error", Toast.LENGTH_LONG).show();
}
}
});
checkIfVerifiedUser(email);
} else {
progressDialog.dismiss();
try {
throw task.getException();
} catch (FirebaseAuthUserCollisionException e) {
// In case the account already exists
checkIfVerifiedUser(email);
} catch (Exception e) {
Toast.makeText(context, R.string.error_auth, Toast.LENGTH_SHORT).show();
}
}
} });
Here is the method I call:
private void checkIfVerifiedUser(String email){
final FirebaseUser user = firebaseAuth.getCurrentUser();
Intent intent = new Intent(context, HomeActivity.class);
if(user != null){
user.reload();
// If the user is created, we check if the account is verified
if(user.isEmailVerified()) {
intent.putExtra(IntentEnum.ALREADYREGISTERED.getCode(), true);
}else{
intent.putExtra(IntentEnum.ALREADYREGISTERED.getCode(), false);
}
}else{
intent.putExtra(IntentEnum.ALREADYREGISTERED.getCode(), false);
}
---rest of code---
}
The problem is that I either get firebaseAuth.getCurrentUser() == null or user.isEmailVerified() always false (even if I click the link in the email I get sent).
Could anyone help me with this?
Thanks!

To solve this, you need to call checkIfVerifiedUser() method inside onComplete() method and inside the if statement.
Hope it helps.

Related

How do I keep a user logged in after they logged in at least once?

How do I keep user loged in after they have signed in one time. I have a register activity that allows the the user to provide their email address and password, and once the user clicks submit an email confirmation is sent and then takes the user to the Login Activity. However once the user gets to the Login Activity they are automatically signed in. I would first like for them to validate their email first and then be signed in and stayed signed in unless they log out. I found some answers on stack-overflow about how to keep the user signed in and how to check if they validated their email but the code that I have skips the validation step and just signs the user in once taken to the login activity.
**Check to see if user enters correct credetials **
public void loginUser(View view) {
if (userEmailEditText.getText().toString().trim().equals("") || userPasswordEditText.getText().toString().trim().equals("")) {
Toast.makeText(LoginActivity.this, "Enter the required information!", Toast.LENGTH_SHORT).show();
} else {
mAuth.signInWithEmailAndPassword(userEmailEditText.getText().toString(), userPasswordEditText.getText().toString())
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
checkUserStatus();
} else {
Toast.makeText(LoginActivity.this, "incorrect info", Toast.LENGTH_SHORT).show();
}
}
});
}
}
**Keeps the user singed in i called this method in onCreate**
public void keepUserSignedIn() {
if (mAuth.getCurrentUser() != null) {
startActivity(new Intent(LoginActivity.this, MainActivity.class));
finish();
}
}
private void createUser() {
mAuth.createUserWithEmailAndPassword(user.getUserEmail(), user.getUserPassword())
.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
//save user info if registration was successful
saveUserInfo();
sendVerificationEmail();
progressDialog.dismiss();
} else {
progressDialog.dismiss();
Log.i("error", task.getResult().toString());
// If sign in fails, display a message to the user.
Toast.makeText(RegisterActivity.this, "Error occurred", Toast.LENGTH_SHORT).show();
}
}
});
}
public void sendVerificationEmail() {
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
if (user != null) {
user.sendEmailVerification()
.addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
Toast.makeText(RegisterActivity.this, "Verify your email...", Toast.LENGTH_SHORT).show();
mAuth.signOut();
startActivity(new Intent(RegisterActivity.this, LoginActivity.class));
}
}
});
}
}
//upload user's credetinals to firebase...
public void saveUserInfo() {
final ProgressDialog progressDialog = new ProgressDialog(this);
progressDialog.setTitle("Uploading...");
//rogressDialog.show();
final String userId = mAuth.getCurrentUser().getUid();
final StorageReference storageRef = FirebaseStorage.getInstance().getReference().child("ProfileImages").child(userId);
storageRef.putFile(selectedImageUri).addOnCompleteListener(new OnCompleteListener<UploadTask.TaskSnapshot>() {
#Override
public void onComplete(#NonNull Task<UploadTask.TaskSnapshot> task) {
if (task.isSuccessful()) {
storageRef.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
#Override
public void onSuccess(Uri uri) {
deviceToken = FirebaseInstanceId.getInstance().getToken();
url = uri.toString();
userDictionary.put("devicetoken", deviceToken);
userDictionary.put("name", user.getUserName().trim());
userDictionary.put("email", user.getUserEmail().trim());
userDictionary.put("lastName", user.getLastName().trim());
userDictionary.put("profileimage", url);
userDictionary.put("user", userId);
mDatabase.child(userId).setValue(userDictionary);
progressDialog.dismiss();
}
//handles error
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
progressDialog.dismiss();
Toast.makeText(RegisterActivity.this, "Error" + e.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
}
});
}
Authenticating the user with Firebase Authentication does not require them to have validated their email address. The two steps are separate, and for good reason.
Once a user signs in, they will normally stay signed in until they sign out. Firebase restores their authentication state when you restart the app, so in most cases things should run smoothly.
If you want a user to only be sent to a certain activity if they've signed in with an account with a verified email address, you can do so with:
FirebaseUser user = mAuth.getCurrentUser();
if (user != null && user.isEmailVerified()) {
...
}

Ambiguous behavior of signInWithEmailAndPassword method

I have an activity namely EmailSignUpActivity from where I am creating a user by leveraging createUserWithEmailAndPassword method from Firebase. After creating a user I am redirecting him to the MainActivity where signOut method is present. After signing out I am redirecting the user to the LoginActivity where email and password login option is present and signing in the user using signInWithEmailAndPassword method.
My problem is that after creating a user for the first time I am signing out the user and again logging in the user immediately in the LoginActivity but none of my log tags which are written inside signInWithEmailAndPassword are working neither the progress dialog is getting dismissed which is written inside the signInWithEmailAndPassword, which shows that this method is not getting called. But when I clear my app from the phone's memory and opening it again then the MainActivity is opening up which was supposed to open up after a successful sign in.
Moreover, when I clear the app from the phone's memory after creating a new user and signing him out and then if I try to log in the user then everything is working fine.
Could anyone explain the reason for this ambiguous behavior?
In EmailSignUpActivity creating the user
mAuth.createUserWithEmailAndPassword(email, password).addOnSuccessListener(new OnSuccessListener<AuthResult>() {
#Override
public void onSuccess(AuthResult authResult) {
progressDialog.dismiss();
Log.d(TAG, "onSuccess: new user created");
Toast.makeText(EmailSignUpActivity.this, "User created", Toast.LENGTH_SHORT).show();
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
progressDialog.dismiss();
Log.w(TAG, "onFailure: user creation failed ", e);
Toast.makeText(EmailSignUpActivity.this, "User already exist", Toast.LENGTH_SHORT).show();
}
});
In LoginActivity signing in the user
private void emailAndPasswordLogin() {
loginButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d(TAG, "onClick:");
progressDialog.show();
String email = emailEditText.getText().toString();
String password = passwordEditText.getText().toString();
if(!email.equals("null") && !password.equals("null")) {
Log.d(TAG, "onClick: mAuth ==> "+mAuth);
mAuth.signInWithEmailAndPassword(email, password).addOnCompleteListener(new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
Log.d(TAG, "onComplete:");
if(task.isSuccessful()){
Log.d(TAG, "onComplete: if task successful");
progressDialog.dismiss();
Log.d(TAG, "onSuccess: login success ");
Boolean newUser = task.getResult().getAdditionalUserInfo().isNewUser();
Log.d(TAG, "LoginButton == onSuccess: newUser ==> "+newUser);
if(newUser){
//
boolean hasImage = false;
enteringDataIntoUserNode(hasImage);
//
Intent intent = new Intent(LoginActivity.this, MainActivity.class);
startActivity(intent);
}else{
Intent intent = new Intent(LoginActivity.this, MainActivity.class);
startActivity(intent);
}
}else{
progressDialog.dismiss();
Log.w(TAG, "onFailure: login failure ", task.getException());
Toast.makeText(LoginActivity.this, "Email or Password invalid.", Toast.LENGTH_SHORT).show();
}
}
});
}
}
});
}
In MainActivity signing out the user
private void signOut() {
// getting the provider id
String providerId = null;
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
for (UserInfo profile : user.getProviderData()) {
Log.d(TAG, "Provider: " + profile.getProviderId());
providerId = profile.getProviderId();
}
if(providerId.equals("password")){
Log.d(TAG, "signOut: inside password sign out");
// firebase sign out
firebaseAuth.signOut();
Log.d(TAG, "signOut: currentUser ==> "+firebaseAuth.getCurrentUser());
Intent intent = new Intent(MainActivity.this, LoginAndSignupActivity.class);
startActivity(intent);
finish();
}
}
Okay try this dont initialize the provider, and when you want to sign out dont get the current user but use this instead. ONLY if you are using firebase UI.
String providerId = profile.getProviderId();
FirebaseAuth.getInstance().signOut(this);
if you are using Firebase Auth, maybe try and Catch to see if your Firebase is logging out in the first place not only switching Intents. I remember i had the same problem and it was regarding my logging out process maybe something like this:
FirebaseAuth mAuth = FirebaseAuth.getInstance();
try {
mAuth.signOut();
Toast.makeText(this, "User Sign out!", Toast.LENGTH_SHORT).show();
}catch (Exception e) {
Log.e(TAG, "onClick: Exception "+e.getMessage(),e );
}

Firebase User Verification Email

I am using Firebase as the Backend for an Mobile Android Application. When a User registers, I would like to have a verification email sent to that user.
When the User Clicks the "SignUp" button, the following logic is run through: First of all a number of variables are set from the filled in boxes. Then a few checks are performed on validity of the filled in parameters. If the checks are passed, a user is created in the Database. This is all functioning..
Then I would like to send a verification email to the user to check if the email is valid. I have also put this in the onClick method of the Button but this is not functioning yet.
I do not receive the verification email.
What is the reason behind this and the fix?
My onCreate Method
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_sign_up_page);
setFontType();
screen = (EditText)findViewById(R.id.SchermNaam);
mail = (EditText)findViewById(R.id.EmailAdres);
knop = (Button)findViewById(R.id.SignUp_Button_SignUp);
firebaseAuth = FirebaseAuth.getInstance();
}
The onClick method for the "SignUp" Button:
public void onClickSignUpPage(View view){
String schermnaam = screen.getText().toString().trim();
String emailadres = mail.getText().toString().trim();
String paswoord = pass.getText().toString().trim();
if(TextUtils.isEmpty(schermnaam)){
Toast.makeText(this,"Schermnaam invullen", Toast.LENGTH_SHORT).show();
return;
}
if(TextUtils.isEmpty(emailadres)){
Toast.makeText(this,"Email invullen",Toast.LENGTH_SHORT).show();
return;
}
if(!schermnaam_ok(schermnaam)){
Toast.makeText(this,"schermnaam minstens 5 en maximum 15 tekens", Toast.LENGTH_SHORT).show();
return;
}
if(!paswoord_ok(paswoord)){
Toast.makeText(this,"paswoord tussen 6-12 karakters en minstens 1 cijfer", Toast.LENGTH_SHORT).show();
return;
}
firebaseAuth.createUserWithEmailAndPassword(emailadres.trim(),paswoord)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if(task.isSuccessful()){
Toast.makeText(SignUpPage.this, "Nieuwe Speler Geregistreerd", Toast.LENGTH_SHORT).show();
Intent intent = new Intent(SignUpPage.this, SignInPage.class);
startActivity(intent);
}
else {
FirebaseAuthException e = (FirebaseAuthException) task.getException();
Toast.makeText(SignUpPage.this,"Fout in de SignUp"+e.getMessage(), Toast.LENGTH_SHORT).show();
Log.d("LoginActivity", "Failed Registration", e);
return;
}
}
});
FirebaseUser user = firebaseAuth.getCurrentUser();
user.sendEmailVerification()
.addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
Log.d(TAG, "Email sent.");
}
}
});
}
Changed it up to a sequential procedure, as suggested by the post quoted by #cramopy. Thank you for this!
Now you first need to "Sign Up" as a user, and then verify in another step, through another button. Then I receive the confirmation email.
Here my code for the onClick method for the 2 Buttons.. From a UX point of view, need to look at how to position the buttons. This is a functional viewpoint.
public void onClickSignUpPage(View view){
String schermnaam = screen.getText().toString().trim();
String emailadres = mail.getText().toString().trim();
String paswoord = pass.getText().toString().trim();
if(TextUtils.isEmpty(schermnaam)){
Toast.makeText(this,"Schermnaam invullen", Toast.LENGTH_SHORT).show();
return;
}
if(TextUtils.isEmpty(emailadres)){
Toast.makeText(this,"Email invullen",Toast.LENGTH_SHORT).show();
return;
}
if(!schermnaam_ok(schermnaam)){
Toast.makeText(this,"schermnaam minstens 5 en maximum 15 tekens", Toast.LENGTH_SHORT).show();
return;
}
if(!paswoord_ok(paswoord)){
Toast.makeText(this,"paswoord tussen 6-12 karakters en minstens 1 cijfer", Toast.LENGTH_SHORT).show();
return;
}
firebaseAuth.createUserWithEmailAndPassword(emailadres.trim(),paswoord)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if(task.isSuccessful()){
Toast.makeText(SignUpPage.this, "Nieuwe Speler Geregistreerd", Toast.LENGTH_SHORT).show();
}
else {
FirebaseAuthException e = (FirebaseAuthException) task.getException();
Toast.makeText(SignUpPage.this,"Fout in de SignUp"+e.getMessage(), Toast.LENGTH_SHORT).show();
Log.d("LoginActivity", "Failed Registration", e);
return;
}
}
});
AddDataFireBase();
}
public void onClickVerify(View view){
FirebaseUser user = firebaseAuth.getCurrentUser();
assert user != null;
user.sendEmailVerification()
.addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
Log.d(TAG, "Email sent.");
}
else {
Log.e(TAG, "sendEmailVerification", task.getException());
Toast.makeText(SignUpPage.this,
"Failed to send verification email.",
Toast.LENGTH_SHORT).show();
}}
});
Intent intent = new Intent(SignUpPage.this, SignInPage.class);
startActivity(intent);
}
Your code should work. But I suggest you to follow the next steps to verify the email:
Create account
Check if creation was successful
Check if the email is verified with user.isEmailVerified()
Reload your user to update the instance with user.reload(). You should do this because some methods on Firebase ask you to reload or reauthenticate the user before realize some operations. Reload in this case will update the cache and data of your user.
Send the email using sendEmailVerification()
Something like:
authInstance.createUserWithEmailAndPassword(email, password)
.addOnCompleteListener {
if (it.isSuccessful) {
//Create accountData in the database
if (it.result!!.user.isEmailVerified) {
it.result!!.user.reload()
.addOnCompleteListener {
if (it.isSuccessful) {
authInstance.currentUser!!.sendEmailVerification()
.addOnCompleteListener {
Log.i("TAG", "Yay! verificationSent")
}
} else {
//Manage error
}
}
}
} else {
//Manage error
}
}
Also, you should know that sometimes the email verification takes some time in Debug environments(at least from my experience I have saw delays of 1-3 minutes, but never on release versions).
Finally, before call user.verify() you should need to call again user.reload() to update the data of your user in the Firebase Cache, if not, even if you have click on Verify my email on the email sent to your account, the FirebaseAuthor.currentUser().isEmailVerified() will continue returning you false.

How to sign in and get user information from database at same time in firebase

I have small firebase project .
User can sign up with email and password and then store profile info photo uri, name, bio and location. So when user sign in first, I will check if the user is authenticated, then if task is successful I will request user info. Is there a way to do two task at same time?
Here is a sample of a code that I am using on my project.
public void loginUserWithEmail(String email, String password) {
mAuth.signInWithEmailAndPassword(email, password).addOnCompleteListener(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("mhstos", "signInWithEmail:success");
user = mAuth.getCurrentUser();
if (user == null) {
//Something went wrong
} else {
userID = user.getUid();
if (userID != null) {
//addListenerForSingleValueEvent will be called once and then removed
mDatabase.child("users").child("email").child(userID).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
//Retrieve the user details
FirebaseNormalUser firebaseNormalUser = dataSnapshot.getValue(FirebaseNormalUser.class);
Log.d("mhstos", firebaseNormalUser.getFirstName() + " " + firebaseNormalUser.getLastName());
if (firebaseNormalUser != null) {
MUser.getInstance().setFirstName(firebaseNormalUser.getFirstName());
MUser.getInstance().setLastName(firebaseNormalUser.getLastName());
MUser.getInstance().setEmail(firebaseNormalUser.getEmail());
MUser.getInstance().setAuthToken(userID);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
}
} else {
// If sign in fails, display a message to the user.
Log.w("mhstos", "signInWithEmail:failure", task.getException());
try {
throw task.getException();
} catch (FirebaseAuthInvalidUserException e) {
Toast.makeText(context, "There is no user record corresponding to this email. Please try again!", Toast.LENGTH_LONG).show();
} catch (FirebaseAuthInvalidCredentialsException e) {
Toast.makeText(context, "The password is invalid. Please try again!", Toast.LENGTH_LONG).show();
} catch (Exception e) {
Log.e("mhstos", e.getMessage());
}
}
}
});
}

Create new user with Names , Username etc in firebase

I'm new android learner so its is difficult for me to do stuffs which I cannot find in the documentation. Here is my code for creating users
mAuth.createUserWithEmailAndPassword(email,password)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if(task.isSuccessful()){
//Successfully Registered
Toast.makeText(RegisterActivity.this, "Registration Successful", Toast.LENGTH_SHORT).show();
}else {
//Error occurred during registration
Toast.makeText(RegisterActivity.this, "Registration Unsuccessful", Toast.LENGTH_SHORT).show();
try {
throw task.getException();
} catch(FirebaseAuthWeakPasswordException e) {
editTextPassword.setError(e.getMessage());
editTextPassword.requestFocus();
}catch(FirebaseAuthUserCollisionException | FirebaseAuthInvalidCredentialsException e) {
editTextEmail.setError(e.getMessage());
editTextEmail.requestFocus();
} catch(Exception e) {
Log.e(RegisterActivity.class.getName(), e.getMessage());
}
}
progressDialog.dismiss();
}
});
This only takes two parameters(email and password) to create an user. To create user with more fields what approach should I take.
I have also added a FirebaseAuth.AuthStateListener() to check user login status. But when I'm calling firebaseAuth.getCurrentUser().getDisplayName() after successfully user login it returns null as usual.So how can I create user with Names so I can retrieve it with firebaseAuth.getCurrentUser().getDisplayName().
After the registration is successful,
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
UserProfileChangeRequest profileUpdates = new UserProfileChangeRequest.Builder()
.setDisplayName("Jane Q. User")
.build();
EDIT: This code is a bit incomplete as profileUpdates is never accessed.
user.updateProfile(profileUpdates)
.addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
Log.d(TAG, "User profile updated.");
}
}
});
Then, to retrieve it, use this wherever required,
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
if (user != null) {
// Name, email address etc
String name = user.getDisplayName();
String email = user.getEmail();
}
To add a user with extra information such as User's name or other required information you should store these data using the Firebase real-time database under the unique user_id generated upon successful completion of email and password registration.
Get user input for name in registration form,
String name = mNameField.getText().toString().trim();
Add user's name in onComplete method :
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if(task.isSuccessful()){
String user_id = mAuth.getCurrentUser().getUid;
DatabaseReference current_user = mDatabase.child(user_id);
current_user.child("name").setValue(name);
progressDialog.dismiss();
}

Categories

Resources