I'm starting a new Android project and decided to use Kotlin and Firebase within, right now I'm able to create users successfully using createUserWithEmailAndPassword on my SignupActivity and my users are logged in successfully when createUserWithEmailAndPassword is finished.
Now I'm trying to get it further using the callback event that is triggered on FirebaseAuth.AuthStateListener using onAuthStateChanged(FirebaseAuth auth) but the listener that I'm creating inside my onCreate(savedInstanceState: Bundle?)function isn't get triggered and my lack of experience converting Java code to Kotlin isn't helping me to identify the root problem.
I have some Java example code to base on that goes like this:
Java 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
}
// ...
}
};
My Kotlin code
FirebaseAuth.AuthStateListener { auth ->
val user = auth.currentUser
if(user != null){
// User is signed in
Log.d(TAG, "Signed in")
Toast.makeText(this, "User", Toast.LENGTH_LONG).show();
sendVerificationEmail()
}else{
// User is signed out
Log.d(TAG, "Signed out")
Toast.makeText(this, "Null", Toast.LENGTH_LONG).show();
}
}
I put some log and toast elements for debugging purpose but neither of them are getting triggered, I'm thinking that the onAuthStateChanged is missing inside the FirebaseAuth.AuthStateListener but I don't know how to fix it.
If anyone can give me some advice on what I'm doing wrong it'll be much appreciate.
Thanks in advance.
This is what has helped me, pay attention on the parenthesis when calling addAuthStateListener - being new to kotlin I used { } curly ones:
public override fun onStart() {
super.onStart()
firebaseAuth.addAuthStateListener(authStateListener)
}
public override fun onPause() {
super.onPause()
firebaseAuth.removeAuthStateListener(authStateListener)
}
Related
I am using firebase authentication for my project. Everything is fine, but when I first install the app from playstore my code is not working, it directly sends the user to main activity. But then if I logout from their it is working fine. And when I first install the app from android studio also then it is working fine, only after installing the app from play store this validation is not working. I am so confused what is wrong with my code, months ago it was working fine, but now it is not working. Can some please help me. In this case I can't even check the what is the value of 'user' here, as I can't use the debugging tools, because it is happening only after installing the app from play store. Please help if someone has any idea about this problem.
#Override
protected void onStart() {
super.onStart();
FirebaseAuth mAuth = FirebaseAuth.getInstance();
FirebaseUser user = mAuth.getCurrentUser();
if (user != null) {
sendUserToMainActivity();
}
}
Use Toast to debug your play store version effectively
if (user != null) {
Toast.makeText(this, user.getUid(), Toast.LENGTH_SHORT).show();
sendUserToMainActivity();
}
And check that Uid with your firebase console.
I'm wondering if something changed in how (or more likely when) the current user is set. Can you try if the app works correctly with an auth state listener? Something like this:
#Override
protected void onStart() {
super.onStart();
FirebaseAuth mAuth = FirebaseAuth.getInstance();
mAuth.addAuthStateListener(new FirebaseAuth.AuthStateListener() {
#Override
public void onAuthStateChanged(#NonNull FirebaseAuth auth) {
FirebaseUser user = auth.getCurrentUser();
if (user != null) {
sendUserToMainActivity();
}
}
});
}
If that works, it seems that FirebaseAuth.getInstance().getCurrentUser() is not yet set by the time your onStart runs.
When i login into my app, it works fine and retrieve data from firebase. But when i close the app and open it later the app don't retrieve it. I need to relogin to get that functioning again. Please help.
You need to listen to onAuthStateChanged listener to detect when the user is ready:
authStateListener = new FirebaseAuth.AuthStateListener() {
#Override
public void onAuthStateChanged(#NonNull FirebaseAuth firebaseAuth) {
if(firebaseAuth.getCurrentUser() != null) {
// User signed in.
} else {
// User signed out.
}
}
};
Is it necessary to add an AuthStateListener in every activity of Android Firebase?
I have added AuthStateListener in login activity.I want to know that is it enough?
I don't think it's necessary. You need to have it in the activity that have to to the sign-in environment setup, or sign out environment clenup in a way like that:
mAuthStateListener = new FirebaseAuth.AuthStateListener() {
#Override
public void onAuthStateChanged(#NonNull final FirebaseAuth firebaseAuth) {
FirebaseUser user = firebaseAuth.getCurrentUser();
if (null != user) {
onSignedInInitialize(user);
} else {
onSignedOutCleanup();
}
}
};
This is usually done by the activity that manage the sign-in process either through FirebaseUI or with the only SDK API.
Remember to do the user reload() in the signin init function so that to manage situations like the case you have deleted a user from the console, the application didn't know that because of caching:
private void onSignedInInitialize(FirebaseUser user) {
user.reload();
if (null != user) {
[...]
You need to have a listener in all the other Activities where you need to respond to events related to the user sign-in, sign-out or updates.
In all other activities all you have to check is only if the user is not null.
if (null != user) {
Where user is the user taken from the the FirebaseAuth instance
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
Usually where you use the listener you create it in the onCreate activity method and you add it in the onResume and remove it in the onPause
#Override
protected void onResume() {
super.onResume();
if (null != mAuthStateListener) {
mFirebaseAuth.addAuthStateListener(mAuthStateListener);
}
}
#Override
protected void onPause() {
super.onPause();
if (null != mAuthStateListener) {
mFirebaseAuth.removeAuthStateListener(mAuthStateListener);
}
}
It really depends on what you want to monitor. According to the docs you'll use this listener to listen to events on:
Right after the listener has been registered
When a user is signed in
When the current user is signed out
When the current user changes
In the activities you need to know those things you should register the listener. But in my experience you'll need register it only in the login activity.
I have a login in my project but always when I open my app after I close it, have to login again. I use Firebase to authenticate, but I want something like:
check if user is logged ->
if not - open login,
else - open my main activity"
I don't know if I have to use SQLite or something or exist how to keep session alive even you close the application if user doesn't log out.
SOLVED! found this and works 100%
#Override
public void onStart() {
super.onStart();
// Check if user is signed in (non-null) and update UI accordingly.
FirebaseUser currentUser = fAuth.getCurrentUser();
updateUI(currentUser);
}
private void updateUI(FirebaseUser user) {
if (user != null) {
startActivity(new Intent(Login.this, MainActivity.class));
} else {
//returns to login
}
}
Because you are using Firebase to autenticate, you can easily verify if a user is autenticated like this:
FirebaseAuth auth = FirebaseAuth.getInstance();
FirebaseAuth.AuthStateListener authListener = new FirebaseAuth.AuthStateListener() {
#Override
public void onAuthStateChanged(#NonNull FirebaseAuth firebaseAuth) {
firebaseUser = firebaseAuth.getCurrentUser();
if (firebaseUser != null) {
Toast.makeText(MainActivity.this, "You are signed in Firebase!", Toast.LENGTH_SHORT).show();
//Redirect to MainActivity
} else {
Toast.makeText(MainActivity.this, "You are signed out from Firebase!", Toast.LENGTH_SHORT).show();
//Redirect to LoginActivity
}
}
};
No need of SqLite. Hope it helps.
If current user is not null, means is logged in, null otherwise
boolean isUserLoggedIn = FirebaseAuth.getInstance().getCurrentUser() != null;
You can set boolean flag when you login on sharedpreferences, so when you load your application you verify that flag, if it's true call some activity but if it's false call login activity.
Just remember to set flag to false when user logout.
I want to implement change password functionality for my application.
I included com.google.firebase:firebase-auth:9.0.2 in my build.gradle file and so far everything has been working fine until I tried to implement change password functionality.
I found that the FirebaseUser object has a updatePassword method that takes a new password as the parameter. I could use this method and implement validation myself. However, I need the user's current password for comparing with the inputted one and I can't find a way to get that password.
I also found another method on the Firebase object that takes the old password, new password, and a handler. The problem is that I need to also include com.firebase:firebase-client-android:2.5.2+ to access this class and when I am trying this method I'm getting to following error:
Projects created at console.firebase.google.com must use the new Firebase Authentication SDKs available from firebase.google.com/docs/auth/
Feel like I'm missing something here. What's the recommended approach for implementing this? And when to use what dependency?
I found a handy example of this in the Firebase docs:
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. When this happens,
re-authenticate the user by getting new sign-in credentials from the
user and passing the credentials to reauthenticate. For example:
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) {
if (task.isSuccessful()) {
user.updatePassword(newPass).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
Log.d(TAG, "Password updated");
} else {
Log.d(TAG, "Error password not updated")
}
}
});
} else {
Log.d(TAG, "Error auth failed")
}
}
});
Changing password in firebase is bit tricky. it's not like what we usually do for changing password in server side scripting and database. to implement change password functionality in your app, first you need to get the user's email from FirebaseAuth or prompt user to input email and after that prompt the user to input old password because you can't retrieve user's password as Frank van Puffelen said. After that you need to reauthenticate that. Once reauthentication is done, if successful, you can use updatePassword(). I have added a sample below that i used for my own app. Hope, it will help you.
private FirebaseUser user;
user = FirebaseAuth.getInstance().getCurrentUser();
final String email = user.getEmail();
AuthCredential credential = EmailAuthProvider.getCredential(email,oldpass);
user.reauthenticate(credential).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if(task.isSuccessful()){
user.updatePassword(newPass).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if(!task.isSuccessful()){
Snackbar snackbar_fail = Snackbar
.make(coordinatorLayout, "Something went wrong. Please try again later", Snackbar.LENGTH_LONG);
snackbar_fail.show();
}else {
Snackbar snackbar_su = Snackbar
.make(coordinatorLayout, "Password Successfully Modified", Snackbar.LENGTH_LONG);
snackbar_su.show();
}
}
});
}else {
Snackbar snackbar_su = Snackbar
.make(coordinatorLayout, "Authentication Failed", Snackbar.LENGTH_LONG);
snackbar_su.show();
}
}
});
}
}
There is no way to retrieve the current password of a user from Firebase Authentication.
One way to allow your users to change their password is to show a dialog where they enter their current password and the new password they'd like. You then sign in (or re-authenticate) the user with the current passwordand call updatePassword() to update it.
I googled something about resetting Firebase passwords and got to this page. It was helpful but didn't get me all the way to the finish line: I still had to Google around for five or ten minutes. So I'm back to improve the answer for VueJS users.
I see lots of code here using "FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();" in the top line. That's a piece of the puzzle mentioned in the most popular two answers.
But I couldn't get that to work in my project, which is written in VueJS. So I had to go exploring.
What I found was another page of the Firebase documentation. It's the same page people are getting the quoted code from (I think), but with the documentation written for Web instead of Android/Java.
So check out the first link if you're here using VueJS. I think it'll be helpful. "Get the currently signed-in user" might contain the appropriate code for your project. The code I found there says:
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// User is signed in.
} else {
// No user is signed in.
}
});
That page I linked up above ("another page") brought me eventually to the "Set a user's password" part of the Web docs. Posters here correctly state that the user must have been authenticated recently to initiate a password update. Try this link for more on re-authenticating users.
"Set a user's password":
// You can set a user's password with the updatePassword method. For example:
var user = firebase.auth().currentUser;
var newPassword = getASecureRandomPassword();
user.updatePassword(newPassword).then(function() {
// Update successful.
}).catch(function(error) {
// An error happened.
});
"Re-authenticate a user"
var user = firebase.auth().currentUser;
var credential;
// Prompt the user to re-provide their sign-in credentials
user.reauthenticateWithCredential(credential).then(function() {
// User re-authenticated.
}).catch(function(error) {
// An error happened.
});
Query revolves around users forgetting their passwords or wishing to reset their passwords via an email letter. Which can be attained by Auth.sendPasswordResetEmail("email#gmail.com");
begin by initializing
private FirebaseAuth mAuth;
private FirebaseAuth.AuthStateListener mAuthListener;
private String DummyEmail = "Dummy#gmail.com"
mAuth = FirebaseAuth.getInstance();
mAuthListener = new FirebaseAuth.AuthStateListener() {
#Override
public void onAuthStateChanged(#NonNull FirebaseAuth firebaseAuth) {
if (firebaseAuth.getCurrentUser() == null) {
}
}
};
Somewhere else when a user requests to update or reset their passwords simply access the mAuth,
private void PassResetViaEmail(){
if(mAuth != null) {
Log.w(" if Email authenticated", "Recovery Email has been sent to " + DummyEmail);
mAuth.sendPasswordResetEmail(DummyEmail);
} else {
Log.w(" error ", " bad entry ");
}
}
Now, needless to burden yourself querying around your database to find whether the Email exits or not, Firebase mAuth will handle that for you.
Is the Email authenticated? Is it active in your Authentication list? Then send a password-reset Email.
The content will look something like this
the reset link will prompt the following dialog on a new web page
Extra
if you're bit nerved by the reset-template "devised" by Firebase. You can easily access and customize your own letter from the Firebase Console.
Authentication > Email templates > Password reset
A simple approach to handle changing a password is to send a password reset email to the user.
FirebaseAuth.getInstance().sendPasswordResetEmail("user#example.org")
.addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
Toast.makeText(Activity.this, "Password Reset Email Sent!"), Toast.LENGTH_LONG).show();
}
else {
Toast.makeText(Activity.this, task.getException().getLocalizedMessage(), Toast.LENGTH_LONG).show();
}
});
This is a kotlin solution to the problem I am putting the method here Hope it helps
// The method takes current users email (currentUserEmail), current users old password (oldUserPassword), new users password (newUserPassword) as parameter and change the user password to newUserPassword
private fun fireBasePasswordChange(
currentUserEmail: String,
oldUserPassword: String,
newUserPassword: String
) {
// To re authenticate the user credentials getting current sign in credentials
val credential: AuthCredential =
EmailAuthProvider.getCredential(currentUserEmail, oldUserPassword)
// creating current users instance
val user: FirebaseUser? = FirebaseAuth.getInstance().currentUser
// creating after successfully re authenticating update password will be called else it will provide a toast about the error ( makeToast is a user defined function here for providing a toast to the user)
user?.reauthenticate(credential)?.addOnCompleteListener { task ->
when {
task.isSuccessful -> {
user.updatePassword(newUserPassword).addOnCompleteListener {
if (it.isSuccessful) {
makeToast("Password updated")
// This part is optional
// it is signing out the user from the current status once changing password is successful
// it is changing the activity and going to the sign in page while clearing the backstack so the user cant come to the current state by back pressing
FirebaseAuth.getInstance().signOut()
val i = Intent(activity, SignInActivity::class.java)
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
startActivity(i)
(activity as Activity?)!!.overridePendingTransition(0, 0)
} else
makeToast("Error password not updated")
}
}
else -> {
makeToast("Incorrect old password")
}
}
}
}