email is not verified - android

in my application first i authenticate user email and then i am verifying user email i have set dialog activity to inform user to check email and verify email i have close button in dialog activity if user click on it dialog will be dismissed
i have implemented override fun onResume() method first activity and in this method i check user have verified email or not by auth.getInstance().currentUser.isEmailVerified
i ran this app i got email and successfully verify but in onResume() method auth.getInstance().currentUser.isEmailVerified returns false
auth.createUserWithEmailAndPassword(binding.email.text.toString(),binding.password.text.toString()).addOnCompleteListener { task->
Log.d("userAuthenticated","yes")
if(task.isSuccessful)
{
val currUser=auth.currentUser
Log.d("TaskIsSuccessful","Yes")
currUser!!.sendEmailVerification().addOnSuccessListener {
Log.d("Emailissent","yes")
uniqueFirebaseAuthId=task.result!!.user!!.uid.toString()
val sentEmailbinding=ActivityEmailVarificationSignUpBinding.inflate(layoutInflater)
val dialog = Dialog(this#SignUp)
dialog.setContentView(sentEmailbinding.root)
dialog.setCanceledOnTouchOutside(true)
dialog.setCancelable(false)
sentEmailbinding.closebtn.setOnClickListener{
dialog.dismiss()
Log.d("Iamback","Yes")
}
dialog.show()
Log.d("verified",currUser.isEmailVerified.toString())
Log.d("Dialogshown","yes")
Log.d("uniqueFirebaseAuthValue","${uniqueFirebaseAuthId} ")
}.addOnFailureListener {
Log.d("emailauthverification",it.toString())
}
}
task.addOnFailureListener {
Log.d("TaskFail",it.toString())
}
onResume() function
override fun onResume() {
super.onResume()
val userEnterdName=binding.uiqueusername.toString()
val currUser=FirebaseAuth.getInstance().currentUser
if(currUser!!.isEmailVerified) {
val verifiedUser=UseratFirebase(userEnterdName,binding.email.toString(),binding.password.toString())
val uniqueAuthId=uniqueFirebaseAuthId.toString()
database.reference.child("users").child(uniqueAuthId).setValue(verifiedUser).addOnSuccessListener {
val intent=Intent(this#SignUp,SignIn::class.java)
intent.putExtra("Email",binding.email.text.toString())
intent.putExtra("password",binding.email.toString())
}.addOnFailureListener {
Toast.makeText(this#SignUp,"Error occured while stroting data",Toast.LENGTH_LONG).show()
}
}
else
{
Log.d("Curruser", "${currUser.toString() } -> ${currUser.isEmailVerified}")
Toast.makeText(this#SignUp,"Please verify Your Account",Toast.LENGTH_LONG).show()
}
}

Verifying the user's email address happens in another application (you click the link in your mail app, and then it verifies that action in the browser), so you app is not aware of it right away.
The information is encoded in the user's ID token, which is refreshed automatically every hour, or when the user signs in again. So you can either wait/force the user to sign in again, or you can tell the SDK to refresh the token by calling user.getIdToken(true) or user.reload().

Related

FIrebase sign in and out options are not working

Can someone explain to me why this simple code is not working properly?
In the beginning I created an object with auth and currentUser
object FirebaseUtils {
val auth: FirebaseAuth = FirebaseAuth.getInstance()
val currentUser: FirebaseUser? = auth.currentUser
}
My login activity function
fun login(){
val email = binding.loginInput.text.toString()
val password = binding.passwordInput.text.toString()
auth.signInWithEmailAndPassword(email, password)
.addOnCompleteListener {
task ->
if (task.isSuccessful){
task.result
Log.d("login_status", "Logged: ${currentUser?.uid}")
startActivity(Intent(this, MainActivity::class.java))
finish()
} else {
Log.d("login_status", task.exception.toString())
}
}
}
Start activity:
lifecycleScope.launch {
delay(2000)
if(currentUser?.uid != null){
Log.d("login_status", "Logged: ${currentUser.uid}")
startActivity(Intent(applicationContext, MainActivity::class.java))
}else{
startActivity(Intent(applicationContext, LoginMainActivity::class.java))
}
finish()
}
And sign out
fun signOut(){
auth.signOut()
startActivity(Intent(this, LoginMainActivity::class.java))
Log.d("login_status", "Signed out: ${currentUser?.uid}")
finish()
}
The problem is that after the first login I can see that logged user is null so my app is crashing (no data for the user). However, after restarting I am logged in as this user. I cant also sign out - activity changes to the login screen but even if I pass different credentials the user remains the same.
EDIT
When I log in and restart the app it works - the correct user is logged.
When I log out and restart the app it also works - the user is signed out.
So why is there a problem between activities
Your result is null because you are getting the result object out of the task object but you aren't doing anything with it. Simply calling:
task.result
Doesn't provide any benefit. However, you can save that result into a variable and call AuthResult#getUser() like this:
val user = task.result.getUser()
Log.d("login_status", "Logged: ${user?.uid}")
So right after you authenticate the user successfully, you'll be able to log the UID correctly.

Firebase Auth emailVerified doesn't updated

hi guys i'm trying to do auto login in my app but before login done i wonder if the user verified his email or no.
the problem : even if i verified my account the code doesn't see this and said false.
and here is my code.
class SignInActivity : BaseActivity<SignInViewModel, ActivitySignInBinding>(), Navigator {
private lateinit var preferenceManger: PreferenceManger
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
preferenceManger = PreferenceManger(applicationContext)
autoLogin()
binding.vm = viewModel
viewModel.navigator = this
addPrefManger()
}
private fun autoLogin() {
DataUtils.firebaseUser = Firebase.auth.currentUser
if (preferenceManger.getBoolean(Constants.KEY_IS_SIGNED_IN)) {
when {
DataUtils.firebaseUser!!.isEmailVerified -> {
startActivity(Intent(this, HomeActivity::class.java))
finish()
}
else -> {
startActivity(Intent(this, VerificationActivity::class.java))
finish()
}
}
}
}
this line is always false even if i verified my account.
DataUtils.firebaseUser!!.isEmailVerified
While the verification status of the user profile is updated on the server as soon as they've clicked the link, it may take up to an hour before that information is synchronized to the Android app.
If you want to detect the email verification in the app before it is automatically synchronized, you can:
Sign the user out and in again.
Force reloading of the user profile (after the user has clicked the link) by calling reload on the user object. You can put a button in your UI to do this, or automatically call that, for example in the onResume of the activity.
Also see:
How to verify email without the need of signing in again while using FirebaseUI-auth?
Verification email activity not refreshing

Firebase authentication onCompleteListener not working when passing fragment activity using requireActivity()

In my current project I need to use MVP pattern. I moved Firebase authentication with onCompleteListener from fragment's OnCreateView to separate file UserModel. This listener requires activity to work. I passed activity using fragment's requireActivity() to LoginPresenter. Presenter then passes activity to UserModel, where sign in is performed.
Sign in works but without working listener I have to restart app in order to close login form.
I tried to change Activity in doLogIn to FragmentActivity but that throws "no interface
method doLogIn" error.
OnCreateView Fragment:
binding.buttonLogin.setOnClickListener {
loginPresenter.doLogin(requireActivity(), email, password)
}
LoginPresenter:
override fun doLogin(activity: Activity, email: String, password: String): Boolean {
user.email = email
user.password = password
return user.doLogIn(activity)
}
UserModel:
override fun doLogIn(activity: Activity): Boolean {
var isLoggedIn = false
auth.signInWithEmailAndPassword(email, password)
.addOnCompleteListener(activity) { task -> // this line is skipped when debugging
if (task.isSuccessful) {
// Sign in success, update UI with the signed-in user's information
Log.d(TAG, "signInWithEmail:success")
isLoggedIn = true
} else {
// If sign in fails, display a message to the user.
Log.w(TAG, "signInWithEmail:failure", task.exception)
}
}
return isLoggedIn
}

Firebase OTP verification onVerificationCompleted not called

I'm trying to set up OTP verification so when the user enters their phone number, I send them a pin code, the onCodeSent() is called and I receive the code pin, but the problem is when onVerificationCompleted() is called, I would like to move to another activity where the user can enter the code pin to verify but it is not called at all and I don't understand why. Any help would be appreciated guys, thank you.
val auth = PhoneAuthOptions
.newBuilder(FirebaseAuth.getInstance())
.setPhoneNumber(phoneNumber)
.setTimeout(60L,TimeUnit.MILLISECONDS)
.setActivity(this)
.setCallbacks(object : PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
override fun onVerificationCompleted(p0: PhoneAuthCredential) {
// here i want to get the smscode and send it over the next activity to verify
// but this method is not called at all
Intent(this,ChangePasswordActivity::class.java).apply {
putExtra("code",p0.smsCode)
startActivity(this)
}
}
override fun onVerificationFailed(p0: FirebaseException) {
Timber.d("Firebase Exception ${p0.message}")
}
override fun onCodeSent(code: String, p1: PhoneAuthProvider.ForceResendingToken) {
super.onCodeSent(code, p1)
}
override fun onCodeAutoRetrievalTimeOut(p0: String) {
super.onCodeAutoRetrievalTimeOut(p0)
}
})
.build()
PhoneAuthProvider.verifyPhoneNumber(auth)
onVerificationCompleted() will only be called when the phone number has been verified without any input from the user. To do what you are trying, you should be sending your intent inside onCodeSent() instead.
Here is a rough flow of events (that are covered in detail in the documentation):
Obtain phone number from user
Call PhoneAuthProvider.verifyPhoneNumber(auth) (as you are already) to send the pin to the user
onCodeSent() is called, with the verification ID and a resending token.
Inside of onCodeSent(), create an intent to launch the "pin input screen" with the verification ID.
Get a pin from the user and then combine it with the verification ID by calling PhoneAuthCredential credential = PhoneAuthProvider.getCredential(verificationId, userInput)
Use that credential to sign in the user using signInWithCredential(credential).
val auth = PhoneAuthOptions
.newBuilder(FirebaseAuth.getInstance())
.setPhoneNumber(phoneNumber)
.setTimeout(60L,TimeUnit.MILLISECONDS)
.setActivity(this)
.setCallbacks(object : PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
override fun onVerificationCompleted(credential: PhoneAuthCredential) {
// if here, phone number was verified automatically
mAuth.signInWithCredential(credential)
.addOnCompleteListener(/* ... */)
}
override fun onVerificationFailed(p0: FirebaseException) {
Timber.d("Firebase Exception ${p0.message}")
}
override fun onCodeSent(verificationId: String, resendToken: PhoneAuthProvider.ForceResendingToken) {
// if here, code was sent to phone number
// open pin input screen
Intent(this,ChangePasswordActivity::class.java).apply {
putExtra("verificationId",verificationId)
startActivity(this)
}
}
// we aren't using onCodeAutoRetrievalTimeOut, so it's omitted.
})
.build()
PhoneAuthProvider.verifyPhoneNumber(auth)
I was also facing this problem but when I added my project to google cloud console, enable api services(google cloud console) and enable phone verification(google cloud console)
then onVerificationCompleted is working fine.
https://console.cloud.google.com/home

Why isn't the variable being updated and returned correctly in this function?

So I've been following a video and Google's documentation trying to implement user sign in with Firebase on an android app. Which is working, so to try and tidy up (and help me reuse the code in another project) I have alot of the sign in code moved to a seperate .kt file and used the below funcion to create a new user.
//in LoginActivity.kt
fun createNewUser(email:String, password:String) :Boolean{
var success:Boolean = false
auth.createUserWithEmailAndPassword(email, password)
.addOnCompleteListener(this) { task ->
if (task.isSuccessful) {
success = true
// Sign in success, update UI with the signed-in user's information
Log.d(null, "createUserWithEmail:success")
val user = auth.currentUser
//updateUI(user)
} else {
// If sign in fails, display a message to the user.
Log.w(null, "createUserWithEmail:failure", task.exception)
//Toast.makeText(baseContext, "Authentication failed.",Toast.LENGTH_SHORT).show()
//updateUI(null)
success = false
}
}
return success
}
The issue I am having is that the "success" boolean isn't being updated when the account is created, the Log saying "success" appears to run fine. I tried changing the inital state of success from false to true and that returned true as expected and my code looking at the result of this ran fine.
Here is where its being called from, as I said the toasts run fine but the value of success returned is always what it was initialised as.
//in MainActivity.kt
var login = LoginActivity()
if(login.createNewUser(email,password)) {
Toast.makeText(this,"I got this far",Toast.LENGTH_SHORT).show()
uploadImageToFirebase()
}
else{
Toast.makeText(this,"I didnt get this far",Toast.LENGTH_SHORT).show()
}
Thanks for any help :)
I'll start at the end, because this is a huge mistake:
var login = LoginActivity()
Never instantiate an Activity. Activity instantiation is handled by the operating system. If createNewUser relies on any functions of LoginActivity, then it will fail when called on your own instantiated instance. And if it doesn't rely on them, then don't define it inside LoginActivity.
Regarding your main question:
When you pass a callback to a function, that means it runs asynchronously. The callback will be called some time in the future, after this function has already returned. So createNewUser can't return the result of the callback.
Instead, you can create your own callback for your function like this. I'm treating auth.currentUser as type User, but you should put whatever class it actually is.
fun createNewUser(email:String, password:String, onComplete: (User?) -> Unit) {
auth.createUserWithEmailAndPassword(email, password)
.addOnCompleteListener(this) { task ->
if (task.isSuccessful) {
// Sign in success, update UI with the signed-in user's information
Log.d(null, "createUserWithEmail:success")
onComplete(auth.currentUser)
} else {
// If sign in fails, display a message to the user.
Log.w(null, "createUserWithEmail:failure", task.exception)
onComplete(null)
}
}
}
Then to use it, you can call the function and in your lambda callback you can react based on whether the user is null or not, which indicates failure or success:
createNewUser(email, password) { user ->
if (user != null) {
// success. Do something with the smart-casted non-null user variable
} else {
// failure. Show error message to the user, etc.
}
}

Categories

Resources