How to verify an email in firebase auth in flutter? - firebase

I've created a login screen using firebase & flutter and Everything is going okay but I want the user to sign in with a real email (verified) not any email.
if the user clicks signs in button with an email like that : shsuhsafk#uisl.com, it will accept this email.
how to verify that the email isn't fake and actually belong to a real address.

In order to really verify the users e-mail address you need to send a verification mail which requires action from the user.
Only checking if the address exists is insufficient as the e-mail address could belong to anyone.
You can set up a mail template in your Firebase Console and use the following code to send the verification mail.
FirebaseUser user = await _firebaseAuth.createUserWithEmailAndPassword(email: email, password: password);
try {
await user.sendEmailVerification();
return user.uid;
} catch (e) {
print("An error occured while trying to send email verification");
print(e.message);
}
}

String email = "user#example.com";
try {
String link = FirebaseAuth.getInstance().generateSignInWithEmailLink(
email, actionCodeSettings);
// Construct email verification template, embed the link and send
// using custom SMTP server.
sendCustomPasswordResetEmail(email, displayName, link);
} catch (FirebaseAuthException e) {
System.out.println("Error generating email link: " + e.getMessage());
}
Please refer Below link for more info: https://firebase.google.com/docs/auth/admin/email-action-links

Related

Flutter FirebaseAuth: SignUp unable to handle error when the email address is used by another user

My code here, and the error pointed at -> await FirebaseAuth.instance
.createUserWithEmailAndPassword(
email: email.trim(), password: password.trim()); - in code below
Future SignUp() async {
try {
UserCredential result = await FirebaseAuth.instance
.createUserWithEmailAndPassword(
email: email.trim(), password: password.trim());
User user = result.user;
return user;
} on FirebaseAuthException catch (e) {
print(e);
if (e.code == 'email-already-in-use') {
setState(
() // setState rebuilds the entire build by modifying the code inside it
{
error = e.toString();
EmailExists =
true; //sets the emailExists variable to 'true' and rebuild
});
}
}
}
Error:
PlatformException (PlatformException(firebase_auth, com.google.firebase.auth.FirebaseAuthUserCollisionException: The email address is already in use by another account., {message: The email address is already in use by another account., additionalData: {}, code: email-already-in-use}, null))
By default Firebase Authentication only allows a single user to register with a specific email address in a project. When a second user tries to register with the same email address, you get the error that you have and you'll need to handle that scenario in your code. Typically you'll tell the user that the email address has already been registered and either ask them for their password, or tell them to use another email address.
If you want to allow multiple users to register with the same email address, you can enable that by changing the Multiple accounts per email address setting in the Sign-in methods pabel of the Firebase console.

what are the error codes for Flutter Firebase Auth Exception?

I have tried to read this thread List of Authorisation errors with Firebase login , and also I have tried to search, but I just can find admin SDK authentication error in here here
those error code from those links are different from the error code for Firebase Auth for Flutter app
I mean, I need the error codes in here
Future<void> signInUsingEmail({required String email, required String password}) async {
try {
await _auth.signInWithEmailAndPassword(email: email, password: password);
} on FirebaseAuthException catch (error) {
// I need the error.code in here
print(error.code);
}
could I know all available error codes? so I can write my own error message in my own language. as for now, I can only catch these error codes below
"too-many-requests"
"wrong-password"
"network-request-failed"
what else?
For the signInWithEmailAndPassword method for Flutter, you will find the error codes in the firebase_auth package documentation.
They are actually the same than the JS SDK ones: https://firebase.google.com/docs/reference/js/firebase.auth.Auth#error-codes_12
For anyone that does not like clicking on links:
signInWithEmailAndPassword
wrong-password: Thrown if the password is invalid for the given email, or the account corresponding to the email doesn't have a password set.
invalid-email: Thrown if the email address is not valid.
user-disabled: Thrown if the user corresponding to the given email has been disabled.
user-not-found: Thrown if there is no user corresponding to the given email.
createUserWithEmailAndPassword
email-already-in-use: Thrown if there already exists an account with the given email address.
invalid-email: Thrown if the email address is not valid.
operation-not-allowed: Thrown if email/password accounts are not enabled. Enable email/password accounts in the Firebase Console, under the Auth tab.
weak-password: Thrown if the password is not strong enough.
signInWithCredential
account-exists-with-different-credential: Thrown if there already exists an account with the email address asserted by the credential. Resolve this by calling fetchSignInMethodsForEmail and then asking the user to sign in using one of the returned providers. Once the user is signed in, the original credential can be linked to the user with linkWithCredential.
invalid-credential: Thrown if the credential is malformed or has expired.
operation-not-allowed: Thrown if the type of account corresponding to the credential is not enabled. Enable the account type in the Firebase Console, under the Auth tab.
user-disabled: Thrown if the user corresponding to the given credential has been disabled.
user-not-found: Thrown if signing in with a credential from EmailAuthProvider.credential and there is no user corresponding to the given email.
wrong-password: Thrown if signing in with a credential from EmailAuthProvider.credential and the password is invalid for the given email, or if the account corresponding to the email does not have a password set.
invalid-verification-code: Thrown if the credential is a PhoneAuthProvider.credential and the verification code of the credential is not valid.
invalid-verification-id: Thrown if the credential is a PhoneAuthProvider.credential and the verification ID of the credential is not valid.id.
reauthenticateWithCredential
user-mismatch: Thrown if the credential given does not correspond to the user.
user-not-found: Thrown if the credential given does not correspond to any existing user.
invalid-credential: Thrown if the provider's credential is not valid. This can happen if it has already expired when calling link, or if it used invalid token(s). See the Firebase documentation for your provider, and make sure you pass in the correct parameters to the credential method.
invalid-email: Thrown if the email used in a EmailAuthProvider.credential is invalid.
wrong-password: Thrown if the password used in a EmailAuthProvider.credential is not correct or when the user associated with the email does not have a password.
invalid-verification-code: Thrown if the credential is a PhoneAuthProvider.credential and the verification code of the credential is not valid.
invalid-verification-id: Thrown if the credential is a PhoneAuthProvider.credential and the verification ID of the credential is not valid.
signInWithAuthProvider
user-disabled: Thrown if the user corresponding to the given email has been disabled.
signInAnonymously
operation-not-allowed: Thrown if anonymous accounts are not enabled. Enable anonymous accounts in the Firebase Console, under the Auth tab.
signInWithEmailLink
expired-action-code: Thrown if OTP in email link expires.
invalid-email: Thrown if the email address is not valid.
user-disabled: Thrown if the user corresponding to the given email has been disabled.
So I created this gist
And it's basically a handler for some common firebase auth exceptions.
This is an example on how to use it
Future createUser(String email, String password) async {
try {
UserCredential customUserCredential = await FirebaseAuth.instance
.createUserWithEmailAndPassword(
email: email, password: password);
return customUserCredential.user!.uid;
} on FirebaseAuthException catch (authError) {
throw CustomAuthException(authError.code, authError.message!);
} catch (e) {
throw CustomException(errorMessage: "Unknown Error");
}
TextButton(
onPressed: () async {
try {
//final user = FirebaseAuth.instance.currentUser;
final email = _emailController.text;
final password = _passwordController.text;
// await FirebaseAuth.instance // final userCredential =
// .signInWithEmailAndPassword(
// email: email, password: password);
AuthService.firebase()
.logIn(email: email, password: password);
final user = AuthService.firebase().currentUser;
if (user?.isEmailVerified ?? false) {
Navigator.of(context).pushNamedAndRemoveUntil(
emailRoute, (route) => false);
} else {
Navigator.of(context)
.pushNamedAndRemoveUntil(noteRoute, (route) => false);
}
//devtools.log(userCredential.toString());
//This line of text may not work to print data
// print(userCredential.toString());
} on FirebaseAuthException catch (e) {
if (e.code == 'network-request-failed') {
showErrorDialog(context, 'No Internet Connection');
//devtools.log('No Internet Connection');
} else if (e.code == "wrong-password") {
return showErrorDialog(
context, 'Please Enter correct password');
//devtools.log('Please Enter correct password');
//print('Please Enter correct password');
} else if (e.code == 'user-not-found') {
showErrorDialog(context, 'Email not found');
// print('Email not found');
} else if (e.code == 'too-many-requests') {
return showErrorDialog(
context, 'Too many attempts please try later');
//print('Too many attempts please try later');
} else if (e.code == 'unknwon') {
showErrorDialog(
context, 'Email and password field are required');
//print('Email and password field are required');
} else if (e.code == 'unknown') {
showErrorDialog(
context, 'Email and Password Fields are required');
//print(e.code);
} else {
print(e.code);
}
}
},
child: const Text('Login')),

Change password of firebase user in flutter

I want to change the password of a firebase account. To do that the user should enter the old password before. If it is correct then he is allowed to change pass. I used this code which is only for changing the pass and not comparing the old one.
void _changePassword(String password) async{
//Create an instance of the current user.
FirebaseUser user = await FirebaseAuth.instance.currentUser();
//Pass in the password to updatePassword.
user.updatePassword(password).then((_){
print("Successfully changed password");
}).catchError((error){
print("Password can't be changed" + error.toString());
//This might happen, when the wrong password is in, the user isn't found, or if the user hasn't logged in recently.
});
}
The idea is to verify old password by resigning in user using firebaseAuth, you can get user email by passing user.email to string, and let user input old password. If sign in proccess failed, password change shouldn't happen.
void _changePassword(String password) async {
FirebaseUser user = await FirebaseAuth.instance.currentUser();
String email = user.email;
//Create field for user to input old password
//pass the password here
String password = "password";
String newPassword = "password";
try {
UserCredential userCredential = await FirebaseAuth.instance.signInWithEmailAndPassword(
email: email,
password: password,
);
user.updatePassword(newPassword).then((_){
print("Successfully changed password");
}).catchError((error){
print("Password can't be changed" + error.toString());
//This might happen, when the wrong password is in, the user isn't found, or if the user hasn't logged in recently.
});
} on FirebaseAuthException catch (e) {
if (e.code == 'user-not-found') {
print('No user found for that email.');
} else if (e.code == 'wrong-password') {
print('Wrong password provided for that user.');
}
}
}
it will not allow you to verify its previous or old password . it will directly send email for forgot and there you need to add your new password . and and you have to back again to application and your password will be updated as you wil try to login .
If the user hasn't signed in recently, Firebase will automatically require them to reauthenticate before they can change their password (or perform other sensitive operations). So you typically should only require the user to reauthenticate when Firebase tells you to.
When that happens, follow the steps in the documentation on reauthenticating a user.

How to handle email verification if trying to return to mobile app after pressing link?

Behavior Wanted: When I press the Sign Up button in my app, it sends a verification link to the specified email and navigates to a verification page within the mobile app that alerts the user that a verification email was sent. Then user can go to own email and click on the link that will verify the user and then direct them back to the verification page where it will reload the user and send them to the home page.
Question: What do I need to do in order to handle this?
Things I have done:
I have a custom domain, let's call it customdomain.com. I have set this up with firebase hosting.
I have created a dynamic link in the firebase console called customdomain.com/verify
I have created ActionCodeSettings to pass to the sendEmailVerification() function:
String url = 'https://customdomain.com/verify/';
String androidPackage = 'com.example.customdomain';
String iosPackage = 'com.example.customdomain';
ActionCodeSettings actionCodeSettings = ActionCodeSettings(url: url, handleCodeInApp: true, android: {"packageName": androidPackage, "installApp": true, "minimumVersion": 21}, iOS: {"bundleId": iosPackage}, dynamicLinkDomain: 'https://customdomain.com/verify');
Future<void> verifyEmail(ActionCodeSettings actionCodeSettings) async {
User userRegister = _auth.currentUser;
if (!userRegister.emailVerified) {
await userRegister.sendEmailVerification(actionCodeSettings);
}
}
I have set my androidManifest.xml and build.gradle to handle dynamic links.
Assumptions Made:
I can use ValueNotifier on my verification page to listen to changes in isEmailVerified.
I need to change my email template to create custom email action handler?(https://firebase.google.com/docs/auth/custom-email-handler ?)
I don't need to create a web page on my customdomain.com to handle email verification.
I will be able to parse the actionCode from the url that was sent to the email for verification.
So just a couple of questions around this. Do I need to have my own custom server in order to handle email verification like this? Can this all be done through the firebase console? When I'm sending the email, am I sending a dynamic link or is the email template sending what is in the console?
I can't find any example of someone implementing this in flutter, so if anyone can point my in the right direction. I've been struggling with thinking about what is it all that I need in order to get this done. If you need more information for clarification, please do let me know.
Do I need to have my own custom server in order to handle email
verification like this? Can this all be done through the firebase
console?
Firebase can handle all the process for email verification in Firebase Auth.
When I'm sending the email, am I sending a dynamic link or is the
email template sending what is in the console?
The email verification sent from Firebase Auth uses the template from the Firebase console.
The Flutter code for sending email verification and verifying the link in the app is similar to what's in the docs for Android.
Sending email link auth/verification
FirebaseAuth _auth = FirebaseAuth.instance;
var emailAuth = "someemail#domain.com";
void sendEmailVerification() {
var acs = ActionCodeSettings(
// URL you want to redirect back to. The domain (www.example.com) for this
// URL must be whitelisted in the Firebase Console.
url: "https://www.example.com/finishSignUp?cartId=1234",
handleCodeInApp: true,
iOSBundleId: "com.example.ios",
androidPackageName: "com.example.android",
androidInstallApp: true,
androidMinimumVersion: "12");
_auth.sendSignInLinkToEmail(
email: emailAuth, actionCodeSettings: acs)
.catchError(
(onError) => print('Error sending email verification $onError'))
.then((value) {
print('Successfully sent email verification');
});
}
Verifying link and sign in
void checkEmailLinkAuth(String emailLink) async {
if (_auth.isSignInWithEmailLink(emailLink)) {
await _auth
.signInWithEmailLink(email: emailAuth, emailLink: emailLink)
.catchError(
(onError) => print('Error signing in with email link $onError'))
.then((value) {
// You can access the new user via value.user
// Additional user info profile *not* available via:
// value.additionalUserInfo.profile == null
// You can check if the user is new or existing:
// value.additionalUserInfo.isNewUser;
var userEmail = value.user;
print('Successfully signed in with email link!');
});
}
}

Firebase confirmation email not being sent

I've set up Firebase email/password authentication successfully, but for security reasons I want the user to confirm her/his email.
It says on Firebases website:
When a user signs up using an email address and password, a confirmation email is sent to verify their email address.
But when I sign up, I doesn't receive a confirmation email.
I've looked and can only find a code for sending the password reset email, but not a code for sending the email confirmation.
I've looked here:
https://firebase.google.com/docs/auth/ios/manage-users#send_a_password_reset_email
anyone got a clue about how I can do it?
I noticed that the new Firebase email authentication docs is not properly documented.
firebase.auth().onAuthStateChanged(function(user) {
user.sendEmailVerification();
});
Do note that:
You can only send email verification to users object whom you created using Email&Password method createUserWithEmailAndPassword
Only after you signed users into authenticated state, Firebase will return a promise of the auth object.
The old onAuth method has been changed to onAuthStateChanged.
To check if email is verified:
firebase.auth().onAuthStateChanged(function(user) {
if (user.emailVerified) {
console.log('Email is verified');
}
else {
console.log('Email is not verified');
}
});
After creating a user a User object is returned, where you can check if the user's email has been verified or not.
When a user has not been verified you can trigger the sendEmailVerification method on the user object itself.
firebase.auth()
.createUserWithEmailAndPassword(email, password)
.then(function(user){
if(user && user.emailVerified === false){
user.sendEmailVerification().then(function(){
console.log("email verification sent to user");
});
}
}).catch(function(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
console.log(errorCode, errorMessage);
});
You can also check by listening to the AuthState, the problem with the following method is, that with each new session (by refreshing the page),
a new email is sent.
firebase.auth().onAuthStateChanged(function(user) {
user.sendEmailVerification();
});
The confirmation email could be in your spam folder.
Check your spam folder.
You can send verification email and check if was verified as follow into the AuthListener:
mAuthListener = new FirebaseAuth.AuthStateListener() {
#Override
public void onAuthStateChanged(#NonNull FirebaseAuth firebaseAuth) {
FirebaseUser user = firebaseAuth.getCurrentUser();
if (user != null) {
//---- HERE YOU CHECK IF EMAIL IS VERIFIED
if (user.isEmailVerified()) {
Toast.makeText(LoginActivity.this,"You are in =)",Toast.LENGTH_LONG).show();
}
else {
//---- HERE YOU SEND THE EMAIL
user.sendEmailVerification();
Toast.makeText(LoginActivity.this,"Check your email first...",Toast.LENGTH_LONG).show();
}
} else {
// User is signed out
Log.d(TAG, "onAuthStateChanged:signed_out");
}
// [START_EXCLUDE]
updateUI(user);
// [END_EXCLUDE]
}
};
if you're using compile "com.google.firebase:firebase-auth:9.2.0" and
compile 'com.google.firebase:firebase-core:9.2.0' the method sendEmailVerification() will not be resolved until you update to 9.8.0 or higher. It wasted most of time before I figured it out.
I have been looking at this too. It seems like firebase have changed the way you send the verification. for me
user.sendEmailVerification()
did not work.
If you get an error such as user.sendEmailVerification() doesn't exist.
use the following.
firebase.auth().currentUser.sendEmailVerification()
It's not the answer to the question but might help someone.
Don't forget to add your site domain to the Authorised domains list under Sign-in-method
You could send a verification email to any user whose email is linked to the Firebase Auth account. For example, in Flutter you could do. something like :
Future<void> signInWithCredentialAndLinkDetails(AuthCredential authCredential,
String email, String password) async {
// Here authCredential is from Phone Auth
_auth.signInWithCredential(authCredential).then((authResult) async {
if (authResult.user != null) {
var emailAuthCredential = EmailAuthProvider.getCredential(
email: email,
password: password,
);
authResult.user
.linkWithCredential(emailAuthCredential)
.then((authResult,onError:(){/* Error Logic */}) async {
if (authResult.user != null) {
await authResult.user.sendEmailVerification().then((_) {
debugPrint('verification email send');
}, onError: () {
debugPrint('email verification failed.');
});
}
});
}
});
}

Resources