Error handling in Password reset flutter firebase - firebase

I am building a Flutter/Firebase app with reset password functionality.
For modularity, I keep my auth functions in an AuthService Class.
class AuthService{
final auth.FirebaseAuth _auth = auth.FirebaseAuth.instance;
// **8** FUNCTION TO RESET PASSWORD
Future<void> resetPassword(String email) async {
try {
return await _auth.sendPasswordResetEmail(email: email);
} catch (e) {
print(e.toString());
}
}
// **8**
}
Then I call it in my widget like this:
final auth = Provider.of<AuthService>(context);
...
await auth.resetPassword(email);
When I add a .then method to go to a route when successful, it redirects to the new route even when there is an error. I have tried to add a .catch method but that throws an exception.
How can I go about this?
await auth.resetPassword(email).then((value) =>
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
const AndroidRecoverySuccess())));
Thanks.

Return bool value after sendPasswordResetEmail, also your Future should return bool. Here is the working code:
Future<bool> resetPassword(String email) async {
try {
await _auth.sendPasswordResetEmail(email: email);
return true;
} catch (e) {
print(e.toString());
return false;
}
}
(optional) You can use FirebaseAuthException for better UX:
Future<bool> resetPassword(String email) async {
try {
await _auth.sendPasswordResetEmail(email: email);
return true;
} on FirebaseAuthException catch (e) {
if (e.code.toString() == 'invalid-email') {
// setState(() {message 'Invalid email address.';});
}
if (e.code.toString() == 'missing-email') {
//...
}
if (e.code.toString() == 'user-not-found') {
//...
}
} catch (e) {
return false;
}
}

Related

Set state inside auth class?

I have the following problem. I want the message to be the correct exception type. i can only use set state within my sign in (because my auth class is not a statlesswidget)class and pass a message there with set state(), but the same for all errors. I've been trying for 9 hours and I can't figure it out. Please help. so I just want the correct exception to be displayed.Something like „The Email adress is badly formated“.the problem is i it dont let me to set the error message be the real error message and i dont know how to fix it
Widget _buildLoginBtn() {
return Container(
padding: EdgeInsets.symmetric(vertical: 25.0),
width: double.infinity,
child: RawMaterialButton(
elevation: 5.0,
padding: EdgeInsets.all(15.0),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30.0),
),
fillColor: Colors.white,
child: Text(
'LOGIN',
style: TextStyle(
color: Color(0xFF527DAA),
letterSpacing: 1.5,
fontSize: 18.0,
fontWeight: FontWeight.bold,
fontFamily: 'OpenSans',
),
),
onPressed: () async {
if (_formKey.currentState.validate()) {
print('valid');
setState(() => loading = false);
dynamic result =
await _auth.signIN(email, password);
if (result == null) {
setState(() => error = 'Check your Input');
loading= false;
}
}
}),
);
}
Future<String> signIN(String email, String password) async {
try {
FirebaseUser user = (await _auth.signInWithEmailAndPassword(
email: email.trim(), password: password)).user;
} catch (e) {
return null;
}
if (user != null) {
print(user);
}
return null;
}
So after im following # Gerpea advice I Get the following error when im just trying to catch the error without the statement on FIREBASEAUTHERROR and when im trying with the statement. When im trying to update my auth and cloud and core it gets me another error.And I can really say if the he ignored the catch block because it don't starts actually when im starting I get as I said before the error in console Im using:
cupertino_icons: ^1.0.2
firebase_auth: ^0.14.0+5
cloud_firestore: ^0.12.9+4
firebase_core_web: ^0.2.1+3
provider: ^4.3.3
flutter_svg: ^0.19.2+1
flutter_spinkit: "^4.1.2"
auto_size_text: ^2.1.0
firebase_core: ^0.4.0
get_it: ^5.0.6
The error ist this:
Invalid depfile: /Users/MYUSERNAME/Desktop/project neu2/flutter_application_2/.dart_tool/flutter_build/7e96e6ced6aa40f9bcd60c2328bbea3e/kernel_snapshot.d
^
../../../flutter/.pub-cache/hosted/pub.dartlang.org/js-0.6.3/lib/js.dart:8:1: Error: Not found: 'dart:js'
export 'dart:js' show allowInterop, allowInteropCaptureThis;
^
../../../flutter/.pub-cache/hosted/pub.dartlang.org/js-0.6.3/lib/js_util.dart:8:1: Error: Not found: 'dart:js_util'
export 'dart:js_util';
^
../../../flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-0.2.1+3/lib/src/interop/utils/js_interop.dart:24:7: Error: Method not found: 'hasProperty'.
if (util.hasProperty(jsObject, 'toDateString')) {
../../../flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-0.2.1+3/lib/src/interop/utils/utils.dart:39:26: Error: Method not found: 'getProperty'.
map[key] = dartify(util.getProperty(jsObject, key), customDartify);
^^^^^^^^^^^
../../../flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-0.2.1+3/lib/src/interop/utils/utils.dart:65:17: Error: Method not found: 'newObject'.
var jsMap = util.newObject();
../../../flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-0.2.1+3/lib/src/interop/utils/utils.dart:67:7: Error: Method not found: 'setProperty'.
util.setProperty(jsMap, key, jsify(value, customJsify));
../../../flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-0.2.1+3/lib/src/interop/utils/utils.dart:73:12: Error: Method not found: 'allowInterop'.
OKafter trying the second correction that #Gerpea send I get the same error so I decide to update to the newest versions go auth.
No I got some problems but I think that's maybe be easyler to correct
but don't really how maybe you know?
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_core_web/firebase_core_web_interop.dart';
import 'package:flutter_application_2/models/user.dart';
class AuthService {
final FirebaseAuth _auth = FirebaseAuth.instance;
String error;
//create user obj based on FirebasedUser
User _userFromFirebaseUser(FirebaseUser user) {
return user != null ? User(uid: user.uid) : null;
}
//auth change user stream
Stream<User> get user {
return _auth.onAuthStateChanged.map(_userFromFirebaseUser);
}
//sign in anon
Future signInAnon() async {
try {
AuthResult result = await _auth.signInAnonymously();
FirebaseUser user = result.user;
return _userFromFirebaseUser(user);
} catch (e) {
print(e.toString());
return null;
}
}
//sign in with passwort and email
Future<String> signIN(String email, String password) async {
try {
FirebaseUser user = (await _auth.signInWithEmailAndPassword(
email: email.trim(),
password: password,
)).user;
} on FirebaseAuthException catch (e) {
switch(e.code) {
case 'user-not-found': {
return 'No user found';
}
default: {
return 'Unexpected error!';
}
}
}
return null;
}
//register with passwort an email
Future<String> signUp(String email, String password) async {
FirebaseUser user = (await _auth.createUserWithEmailAndPassword(
email: email, password: password)) .user;
try {
await user.sendEmailVerification();
return user.uid;
} catch (e) {
print(e.toString);
return null;
}
}
//sign out
Future signOut() async {
try {
return await _auth.signOut();
} catch (e) {
print(e.toString());
return null;
}
}
//resetpassword
Future<void> sendPasswordResetEmail(String email) async {
try {
return await _auth.sendPasswordResetEmail(email: email);
} catch (e) {
print(e.toString());
return null;
}
}
}
that's the exceptions
enter image description here
OK now it logs very good I just have 2 exceptions. Code looks like that:
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter_application_2/models/user.dart' as Model;
class AuthService {
final FirebaseAuth _auth = FirebaseAuth.instance;
String error;
//create user obj based on FirebasedUser
Model.User _userFromFirebaseUser(Model.User user) {
return user != null ? Model.User(uid: user.uid) : null;
}
//auth change user stream
Stream<Model.User> get user {
return _auth.onAuthStateChanged.map(_userFromFirebaseUser);
}
//sign in anon
Future signInAnon() async {
try {
UserCredential result = await _auth.signInAnonymously();
User user = result.user;
return _userFromFirebaseUser(user);
} catch (e) {
print(e.toString());
return null;
}
}
//sign in with passwort and email
Future<String> signIN(String email, String password) async {
try {
User user = (await _auth.signInWithEmailAndPassword(
email: email.trim(),
password: password,
)).user;
} on FirebaseAuthException catch (e) {
switch(e.code) {
case 'user-not-found': {
return 'No user found';
}
default: {
return 'Unexpected error!';
}
}
}
return null;
}
//register with passwort an email
Future<String> signUp(String email, String password) async {
User user = (await _auth.createUserWithEmailAndPassword(
email: email, password: password)) .user;
try {
await user.sendEmailVerification();
return user.uid;
} catch (e) {
print(e.toString);
return null;
}
}
//sign out
Future signOut() async {
try {
return await _auth.signOut();
} catch (e) {
print(e.toString());
return null;
}
}
//resetpassword
Future<void> sendPasswordResetEmail(String email) async {
try {
return await _auth.sendPasswordResetEmail(email: email);
} catch (e) {
print(e.toString());
return null;
}
}
}
And EXCEptions like that:
enter image description here
#Gerpea
So here's my code
Future<String> signUp(String email, String password, String fullname,String user) async {
try {
( await _auth.createUserWithEmailAndPassword(
email: email.trim(), password: password,)).user.sendEmailVerification();
await DatbaseService(uid: user.uid).updateUserData('username', 'fullname', 'Passwort', 'Email');
} on FirebaseAuthException catch (e) {
And the method from YouTube:
Future registerWithEmailAndAPassword(String email, String,Passwort)async {
try{
AuthResult result = await.createUserWithEmailAndPassowrd(email:email,password:password);
FirebaseUser user =result.user;
await DatabaseService(uid:user.uid).updateUserData('0','new crew member',100);
return _userFromFirebaseUser(user);
}catch (e){
signInWithEmailAndPassword() method in case of error will throw a FirebaseAuthException which contain code field with error code.
The full list of errors for this method can be found here.
So you can rewrite you method a bit, to return an error message instead just null.
Future<String> signIN(String email, String password) async {
try {
User user = (await _auth.signInWithEmailAndPassword(
email: email.trim(),
password: password,
)).user;
} on FirebaseAuthException catch (e) {
switch(e.code) {
case 'user-not-found': {
return 'No user found';
}
default: {
return 'Unexpected error!';
}
}
}
return null;
}
Now this method return null if there is no error and String if some error occurs.
Use this in onPressed callback.
onPressed: () async {
if (_formKey.currentState.validate()) {
print('valid');
String authError = await _auth.signIN(email, password);
if (authError != null) {
setState(() => error = authError);
}
setState(() => loading = false);
}
}
firebase_auth: ^0.14.0+5
This is a bit outdated and has some problems, so it will be better if you
will upgrade your dependencies.
But if you can't upgrade. This should work.
Future<String> signIN(String email, String password) async {
try {
FirebaseUser user = (await _auth.signInWithEmailAndPassword(
email: email.trim(),
password: password,
)).user;
} on AuthException catch (e) {
switch(e.code) {
case 'ERROR_USER_NOT_FOUND': {
return 'No user found';
}
default: {
return 'Unexpected error!';
}
}
} catch(e) {
return 'Some error that FirebaseAuth do not catch'!;
}
return null;
}
List of error codes can be found here.

I have some problems in Flutter Firebase Login

I am coding an app for my company and I tried to add firebase authentication for login and registration to my app. The app shows no error and runs successfully.
But when a user tries to login with the wrong email and password, it is showing an internal flutter error instead of the toast I have programmed. And also I have used shared preferences to make users stay logged in.
So when a user tried to log in with the wrong credential it is showing an internal flutter error and when the app is re-opened, instead of going to the login screen, it is using the wrong credential and navigates user to Home Screen which is ridiculous.
These are the declared variables:
final FirebaseAuth firebaseAuth = FirebaseAuth.instance;
final _formKey = GlobalKey<FormState>();
TextEditingController _emailcontroller = TextEditingController();
TextEditingController _passwordcontroller = TextEditingController();
bool passvis = true;
bool loading = false;
And this is the function for login:
Future loginForm() async {
FormState formSate = _formKey.currentState;
if (formSate.validate()) {
final User firebaseUser = (await firebaseAuth
.signInWithEmailAndPassword(
email: _emailcontroller.text,
password: _passwordcontroller.text)
.catchError((errMsg) {
displayToast("Error: " + errMsg.toString(), context);
}))
.user;
if (firebaseUser != null) {
setState(() {
loading = true;
});
usersRef.child(firebaseUser.uid).once().then((DataSnapshot snap) {
if (snap.value != null) {
Navigator.pushReplacement(context,
MaterialPageRoute(builder: (context) {
return LocationHome();
}));
displayToast("Succesfully LoggedIn!", context);
} else {
firebaseAuth.signOut();
displayToast("No user found! Please try SignUp", context);
}
});
} else {
displayToast("Error Occured! Cannot log you in", context);
}
}
}
}
And for Registration the code is below:
Future validateForm() async {
FormState formSate = _formKey.currentState;
if (formSate.validate()) {
final User firebaseUser = (await firebaseAuth
.createUserWithEmailAndPassword(
email: _emailcontroller.text,
password: _passwordcontroller.text)
.catchError((errMsg) {
displayToast("Error: " + errMsg.toString(), context);
}))
.user;
if (firebaseUser != null) {
Map userDataMap = {
"name": _namecontroller.text.trim(),
"email": _emailcontroller.text.trim(),
"phone": _phonecontroller.text.trim(),
};
usersRef.child(firebaseUser.uid).set(userDataMap);
displayToast("Succesfully Registered!", context);
Navigator.pushReplacement(context,
MaterialPageRoute(builder: (context) {
return LocationHome();
}));
} else {
displayToast("User was unable to create", context);
}
}
}
}
The main.dart file is also coded correctly:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
SharedPreferences preferences = await SharedPreferences.getInstance();
var circle = preferences.getString("circle");
runApp(MaterialApp(
title: 'TaakStore',
home: circle == null ? Login() : Home(),
));
}
DatabaseReference usersRef =
FirebaseDatabase.instance.reference().child("users");
Dont worry about the displayToast function. It is a function manually created with flutter toast.
To display a toast, try the following:
try {
await FirebaseAuth.instance.signInWithEmailAndPassword(
email: _emailcontroller.text,
password: _passwordcontroller.text
);
} on FirebaseAuthException catch (e) {
displayToast("Error: " + e.message.toString(), context);
print(e.message);
}
To check if the user is logged in or not use the following:
FirebaseAuth.instance
.authStateChanges()
.listen((User user) {
if (user == null) {
print('User is currently signed out!');
} else {
print('User is signed in!');
}
});
authStateChanges() is of type Stream<User> which will listen for any changes on the state of a user. So if user is logged in, it will return a valid user object and you can navigate to the home screen. Therefore no need to use shared preferences.
To display a toast
try {
await FirebaseAuth.instance.signInWithEmailAndPassword(
email: _emailcontroller.text,
password: _passwordcontroller.text
);
} on FirebaseAuthException catch (e) {
displayToast("Error: " + e.message.toString(), context);
print(e.message);
}
To check if the user is logged in
//inside the main.dart in the "MaterialApp" widget
MaterialApp(home:buildHome(),)
buildHome(){return StreamBuilder(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (BuildContext context, AsyncSnapshot<User> snapshot) {
if (snapshot.hasData) {
print(snapshot);
//if the user is logged in return what you want
return "";
} else {
//else return what you want also
return"";
}
},
);}

Failed to return to login page/screen after signing out (Not sure if sign out is successful or not)

I'm new in flutter and dealing with backend. I faced problem in signing out and I don't know how to fix it due to lack of experience. When I sign out, it would not return to the login screen (Authenticate). I'm not quite sure if the problem lies at the function I wrote at the wrapper or somewhere in auth.
The wrapper widget will be executed everytime the app runs:
void main(){
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return StreamProvider<User>.value(
value: AuthService().user,
child: new MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
primaryColor: Colors.redAccent,
),
home: Wrapper(),
),
);
}
}
The wrapper code is as below:
class Wrapper extends StatelessWidget {
#override
Widget build(BuildContext context) {
final user = Provider.of<User>(context);
print(user);
if (user == null) {
return Authenticate();
} else {
return MyBottomNavigationBar();
}
}
}
Sign out button function:
onPressed: () async {
await _auth.signOut();
print('signing out');
},
Auth code:
import 'package:firebase_auth/firebase_auth.dart';
import 'package:mudah_replica/models/user.dart';
class AuthService {
final FirebaseAuth _auth = FirebaseAuth.instance;
//Create user object based on FirebaseUser
User _userFromFirebaseUser(FirebaseUser user){
return user != null ? User(uid: user.uid) : null;
}
//Auth change user stream
Stream<User> get user {
return _auth.onAuthStateChanged
//.map((FirebaseUser user) => _userFromFirebaseUser(user));
.map(_userFromFirebaseUser);
}
//Sign in anonymously
Future signInAnon() async {
try {
AuthResult result = await _auth.signInAnonymously();
FirebaseUser user = result.user;
return user;
} catch(e) {
print(e.toString());
return null;
}
}
//Sign in with Email & Password
Future signInWithEmailAndPassword(String email, String password) async {
try {
AuthResult result = await _auth.signInWithEmailAndPassword(email: email, password: password);
FirebaseUser user = result.user;
return _userFromFirebaseUser(user);
} catch(e){
print(e.toString());
return null;
}
}
//Register with Email & Password
Future registerWithEmailAndPassword(String email, String password) async {
try {
AuthResult result = await _auth.createUserWithEmailAndPassword(email: email, password: password);
FirebaseUser user = result.user;
return _userFromFirebaseUser(user);
} catch(e){
print(e.toString());
return null;
}
}
//Sign out
Future signOut() async {
try{
return await _auth.signOut();
} catch(e){
print('Fail to sign out');
print(e.toString());
return null;
}
}
}
in your wrapper class, you are returning auth widget instead of navigate to the right screen, so it doesn't route. Instead, you might wanna navigate to the Auth screen. Do something like this:
onPressed: () async {
await _auth.signOut();
Navigator.push(context,
MaterialPageRoute(builder: (context) => Authenticate())
},

Firebase.instance.signOut() not setting the currentUser() to null

Why is my signOut() method not setting the currentUser() to null??
When I click on logout on my homepage it checks the isAuthenticated() method which is returning a user instead of null. Also, just have a look at the two comments I've included inside the logout() method.
Thank You!!
Here's my code -
class Auth with ChangeNotifier {
final FirebaseAuth _auth = FirebaseAuth.instance;
final GoogleSignIn _googleSignIn = GoogleSignIn();
bool isAuthenticated() {
print('$currentUser inside the isAuthenticated');
if (currentUser == null) {
print('false');
return false;
}
print('true');
return true;
}
Future<FirebaseUser> get currentUser async {
return await _auth.currentUser();
}
Future<FirebaseUser> signInWithEmail(String email, String password) async {
try {
final response = await _auth.signInWithEmailAndPassword(
email: email,
password: password,
);
print(response);
if (response == null) {
print('response is null');
} else {
notifyListeners();
return response.user;
}
} catch (error) {
print('some error');
throw error;
}
}
Future<FirebaseUser> signInWithGoogle() async {
try {
final GoogleSignInAccount _userDetails = await _googleSignIn.signIn();
if (_userDetails == null) {
print('No user found');
} else {
final GoogleSignInAuthentication googleAuth =
await _userDetails.authentication;
final AuthCredential credential = GoogleAuthProvider.getCredential(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
final FirebaseUser user =
(await _auth.signInWithCredential(credential)).user;
return user;
}
notifyListeners();
print('google sign in ran successfully');
} catch (error) {
throw error;
}
}
Future<FirebaseUser> logout() async {
try {
print('logout ran');
print(currentUser); //THIS RETURNS AN INSTANCE OF USER
_auth.signOut().then( (response) {
print('signout successful');
});
await _googleSignIn.signOut();
print(currentUser); //THIS *ALSO* RETURNS AN INSTANCE OF USER
notifyListeners();
return currentUser;
} catch (error) {
print('an error');
}
}
}
I know there would a silly mistake that I'm unable to catch but it's tiring now!! I've tried other methods that I could find on stackoverflow
May be the future is not complete when you try getting current user, have you tried await instead of then in logout?
Future<FirebaseUser> logout() async {
try {
print('logout ran');
print(currentUser); //THIS RETURNS AN INSTANCE OF USER
await _auth.signOut();
await _googleSignIn.signOut();
//The problem is with this, you need to await this
//print(currentUser); //THIS *ALSO* RETURNS AN INSTANCE OF USER
var user = await currentUser;
print(user); //prints null
notifyListeners();
return currentUser;
} catch (error) {
print('an error');
}
}
I faced similar issue and worked it around by assigning null to currentUser. It works fine now!
case R.id.main_logout_option:
updateUserStatus(getString(R.string.strOffline));
mAuth.signOut();
currentUser = null;
goToLoginActivity();
break;

Login even after wrong creditionals flutter firebase

i get navigate to the home page even i entered the wrong credentials. i get the error that 'no user fond' but how to stop it.
signIn() async {
if (formkey.currentState.validate()) {
formkey.currentState.save();
try {
_auth.signInWithEmailAndPassword(email: email, password: password);
Navigator.push(context, MaterialPageRoute(builder: (context)=> Home()));
} catch (e) {
print(e.message);
}
}
}
It looks like you're not awaiting for any response from auth.signInWithEmailAndPassword which is what you'd need to do in order to check and see if they're actually authenticated.
So:
await _auth.signInWithEmailAndPassword(email: email, password: password);
When I run this code:
try {
await FirebaseAuth.instance.signInWithEmailAndPassword(email: "nope#stackhack.com", password: "secret");
print("Signed in");
}
catch (e) {
print(e);
}
I get the error printed, and not the "Signed in" message. The error contains a code property, which has a value "ERROR_USER_NOT_FOUND". So to respond to this specific error, I could do something like:
if (e.code == "ERROR_USER_NOT_FOUND") {
print("User not found");
}
There are 2 solutions, one is
signIn() async {
if (formkey.currentState.validate()) {
formkey.currentState.save();
try {
FirebaseUser user = await _auth.signInWithEmailAndPassword(email: email, password: password);
if (user != null && await user.getIdToken() != null) {
final FirebaseUser currentUser = await auth.currentUser();
if (currentUser.uid == user.uid) {
print("Success in signing, you can now navigate");
Navigator.push(context, MaterialPageRoute(builder: (context) => Home()));
}
}
} catch (e) {
print(e.message);
}
}
}
other is (thanks to Frank)
signIn() async {
if (formkey.currentState.validate()) {
formkey.currentState.save();
try {
await FirebaseAuth.instance.signInWithEmailAndPassword(email: "nope#stackhack.com", password: "secret");
print("Signed in, you may want to navigate now");
Navigator.push(context, MaterialPageRoute(builder: (context) => Home()));
}
catch (e) {
if (e.code == "ERROR_USER_NOT_FOUND") {
print("User not found");
}
}
}
}

Resources