Wednesday, June 12, 2024
Google search engine
HomeUncategorizedAuthentication Error Handling in Flutter

Authentication Error Handling in Flutter

Quick Blog Guide Explaining the Common Error Encountered During Authentication

Introduction

In this blog, we shall discuss about handing authentication exception. When the user signs in or signup he might get some error but if we do not handle those errors the user will not be able to know about the authentication failure. So it is very important to handle those errors and display a message or alert so that the user can change his credentials as per the requirement of the error.


Table of contents:

Validating TextField

Handle platform exception.

Handle Firebase Auth exceptions

Complete auth module


Validating TextField

Email TextField

TextFormField(
key: ValueKey('email'),
autocorrect: false,
textCapitalization: TextCapitalization.none,
enableSuggestions: false,
validator: (value) {
if (value.isEmpty || !value.contains('@')) {
return 'Please enter a valid email address.';
}
return null;
},
keyboardType: TextInputType.emailAddress,
)

: TextFormField provides us validator property to show an error if the email is empty or it does not contain @. You can add as many error messages you want using nested if-else.

Password TextField

TextFormField(
key: ValueKey('password'),
validator: (value) {
if (value.isEmpty || value.length < 7) {
return 'Password must be at least 7 characters long.';
}
return null;
},
obscureText: hidePassword,

)

Handle Platform exception

This handle the error of different platforms such as android and ios

try {
if (isLogin) {
userCredential = await _auth.signInWithEmailAndPassword(
email: email,
password: password,
);
} else if (password == confirmPassword) {
userCredential = await _auth.createUserWithEmailAndPassword(
email: email,
password: password,
);
} else {}
} on PlatformException catch (err) {
authProblems errorType;
if (Platform.isAndroid) {
switch (e.message) {
case 'There is no user record corresponding to this identifier. The user may have been deleted.':
errorType = authProblems.UserNotFound;
break;
case 'The password is invalid or the user does not have a password.':
errorType = authProblems.PasswordNotValid;
break;
case 'A network error (such as timeout, interrupted connection or unreachable host) has occurred.':
errorType = authProblems.NetworkError;
break;
default:
print('Case ${e.message} is not yet implemented');
}
} else if (Platform.isIOS) {
switch (e.code) {
case 'Error 17011':
errorType = authProblems.UserNotFound;
break;
case 'Error 17009':
errorType = authProblems.PasswordNotValid;
break;
case 'Error 17020':
errorType = authProblems.NetworkError;
break;
// ...
default:
print('Case ${e.message} is not yet implemented');
}
}
Scaffold.of(ctx).showSnackBar(
SnackBar(
content: Text($errorType),
backgroundColor: Theme.of(ctx).errorColor,
),
);
}

Handling both platform error using a single code

var errorMessage;
final _auth = FirebaseAuth.instance;

try {
if (isLogin) {
userCredential = await _auth.signInWithEmailAndPassword(
email: email,
password: password,
);
} else if (password == confirmPassword) {
userCredential = await _auth.createUserWithEmailAndPassword(
email: email,
password: password,
);
}

} on PlatformException catch (err) {
var message = 'An error occurred, please check your credentials!';

if (err.message != null) {
message = err.message;
setState(() {
errorMessage = message;
});
print(message);
}
Scaffold.of(ctx).showSnackBar(
SnackBar(
content: Text(message),
backgroundColor: Theme.of(ctx).errorColor,
),
);
}

Here we are directly displaying the error message using a snack bar. If the error message is null then ‘An error occurred, please check your credentials!’ message will be displayed. If an error message is not null then message = err.message; .

Handle Firebase Auth exceptions

catch (error) {
print(error);
setState(() {
errorMessage = error.toString();
});
Scaffold.of(ctx).showSnackBar(
SnackBar(
content: Text(errorMessage),
backgroundColor: Colors.red,
),
);
}

While logging in user can get the following error :

  • [firebase_auth/wrong-password] The password is invalid or the user does not have a password.
  • [firebase_auth/invalid-email] The email address is badly formatted.
  • [firebase_auth/user-not-found] There is no user record corresponding to this identifier. The user may have been deleted.

While Signing up user can get the following error:

  • [firebase_auth/email-already-in-use] The email address is already in use by another account.
  • [firebase_auth/invalid-email] The email address is badly formatted.
  • [firebase_auth/weak-password] Password should be at least 6 characters.
Types of error

Complete auth module (Ready to use)

Complete Dart Code File for Auth Form :

import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_vector_icons/flutter_vector_icons.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:laundary_application/widgets/userImagePicker.dart';

class AuthForm extends StatefulWidget {
AuthForm(
this.submitFn,
this.isLoading,
);

final bool isLoading;
final void Function(
String email,
String password,
String confirmPassword,
String userName,
File image,
bool isLogin,
BuildContext ctx,
) submitFn;

@override
_AuthFormState createState() => _AuthFormState();
}

class _AuthFormState extends State<AuthForm> {
final _formKey = GlobalKey<FormState>();
var _isLogin = true;
var _userEmail = '';
var _userName = '';
var _userPassword = '';
var _confirmPassword = '';
File _userImageFile;
bool hidePassword = true;

void _pickedImage(File image) {
_userImageFile = image;
}

void _trySubmit() {
final isValid = _formKey.currentState.validate();
FocusScope.of(context).unfocus();

if (_userImageFile == null && !_isLogin) {
Scaffold.of(context).showSnackBar(
SnackBar(
content: Text('Please pick an image.'),
backgroundColor: Theme.of(context).errorColor,
),
);
return;
}

if (isValid) {
_formKey.currentState.save();
widget.submitFn(
_userEmail.trim(),
_userPassword.trim(),
_confirmPassword.trim(),
_userName.trim(),
_userImageFile,
_isLogin,
context,
);
}
}

@override
Widget build(BuildContext context) {
double width = MediaQuery.of(context).size.width;
double height = MediaQuery.of(context).size.height;
return Center(
child: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.all(16),
child: Form(
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
!_isLogin
? SizedBox(
height: 0,
)
: Image.asset(
"assets/appIcon.png",
height: height * 0.2,
),
if (!_isLogin) UserImagePicker(_pickedImage, widget.isLoading),
Container(
width: width,
height: 50,
decoration: BoxDecoration(
border: Border.all(
color: Colors.grey.withOpacity(0.5),
width: 1,
),
borderRadius: BorderRadius.circular(5),
),
child: TextFormField(
key: ValueKey('email'),
autocorrect: false,
textCapitalization: TextCapitalization.none,
enableSuggestions: false,
validator: (value) {
if (value.isEmpty || !value.contains('@')) {
return 'Please enter a valid email address.';
}
return null;
},
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
hintText: 'Email address',
prefixIcon: Icon(Entypo.mail),
border: InputBorder.none),
onSaved: (value) {
_userEmail = value;
},
),
),
SizedBox(height: 12),
if (!_isLogin)
Container(
width: width,
height: 50,
decoration: BoxDecoration(
border: Border.all(
color: Colors.grey.withOpacity(0.5),
width: 1,
),
borderRadius: BorderRadius.circular(5),
),
child: TextFormField(
key: ValueKey('username'),
autocorrect: true,
textCapitalization: TextCapitalization.words,
enableSuggestions: false,
validator: (value) {
if (value.isEmpty || value.length < 4) {
return 'Please enter at least 4 characters';
}
return null;
},
decoration: InputDecoration(
hintText: 'Username',
prefixIcon: Icon(Icons.edit),
border: InputBorder.none,
),
onSaved: (value) {
_userName = value;
},
),
),
SizedBox(height: 12),
Container(
width: width,
height: 50,
decoration: BoxDecoration(
border: Border.all(
color: Colors.grey.withOpacity(0.5),
width: 1,
),
borderRadius: BorderRadius.circular(5),
),
child: TextFormField(
key: ValueKey('password'),
validator: (value) {
if (value.isEmpty || value.length < 7) {
return 'Password must be at least 7 characters long.';
}
return null;
},
decoration: InputDecoration(
suffixIcon: IconButton(
icon: Icon(
hidePassword ? Entypo.eye_with_line : Entypo.eye),
onPressed: () {
setState(() {
hidePassword = !hidePassword;
});
},
),
hintText: 'Password',
border: InputBorder.none,
prefixIcon: Icon(
Icons.vpn_key,
)),
obscureText: hidePassword,
onSaved: (value) {
_userPassword = value;
},
),
),
SizedBox(height: 12),
if (!_isLogin)
Container(
width: width,
height: 50,
decoration: BoxDecoration(
border: Border.all(
color: Colors.grey.withOpacity(0.5),
width: 1,
),
borderRadius: BorderRadius.circular(5),
),
child: TextFormField(
key: ValueKey('password'),
validator: (value) {
if (value.isEmpty || value.length < 7) {
return 'Password must be at least 7 characters long.';
}
return null;
},
decoration: InputDecoration(
hintText: 'Confirm Password',
border: InputBorder.none,
prefixIcon: Icon(
Icons.vpn_key,
)),
obscureText: hidePassword,
onSaved: (value) {
_confirmPassword = value;
},
),
),
SizedBox(height: 12),
widget.isLoading
? CircularProgressIndicator()
: InkWell(
onTap: _trySubmit,
child: Container(
height: 50,
decoration: BoxDecoration(
color: Colors.pinkAccent.withOpacity(0.8),
borderRadius: BorderRadius.circular(5),
),
width: width,
child: Center(
child: Text(
_isLogin ? 'Login' : 'Sign Up',
style: GoogleFonts.lato(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.w900,
),
)),
),
),
if (!widget.isLoading)
FlatButton(
child: RichText(
text: TextSpan(children: [
TextSpan(
text: _isLogin
? "Don't have an account? "
: "Already have an account?",
style: GoogleFonts.lato(
color: Colors.black54,
)),
TextSpan(
text: _isLogin ? "Sign Up" : "Log In",
style: GoogleFonts.lato(
color: Colors.red,
fontWeight: FontWeight.w900,
)),
]),
),
onPressed: () {
setState(() {
_isLogin = !_isLogin;
});
},
),
Image.asset(
"assets/demo1.png",
height: height * 0.26,
),
],
),
),
),
),
);
}
}

Let us Have a look at the authentication dart file :

import 'dart:io';

import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/services.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:laundary_application/widgets/authForm.dart';

class AuthScreen extends StatefulWidget {
@override
_AuthScreenState createState() => _AuthScreenState();
}

class _AuthScreenState extends State<AuthScreen> {
final _auth = FirebaseAuth.instance;
var _isLoading = false;
var errorMessage;

void _submitAuthForm(
String email,
String password,
String confirmPassword,
String username,
File image,
bool isLogin,
BuildContext ctx,
) async {
UserCredential userCredential;

try {
setState(() {
_isLoading = true;
});
if (isLogin) {
userCredential = await _auth.signInWithEmailAndPassword(
email: email,
password: password,
);
} else if (password == confirmPassword) {
userCredential = await _auth.createUserWithEmailAndPassword(
email: email,
password: password,
);

final ref = FirebaseStorage.instance
.ref()
.child('user_image')
.child(userCredential.user.uid + '.jpg');

await ref.putFile(image).onComplete;

final url = await ref.getDownloadURL();

await FirebaseFirestore.instance
.collection('users')
.doc(userCredential.user.uid)
.set({
'username': username,
'email': email,
'image_url': url,
});
} else {
setState(() {
_isLoading = false;
errorMessage = "password does not match";
Scaffold.of(ctx).showSnackBar(
SnackBar(
content: Text(errorMessage),
backgroundColor: Colors.red,
),
);
});
}
} on PlatformException catch (err) {
var message = 'An error occurred, please check your credentials!';

if (err.message != null) {
message = err.message;
setState(() {
errorMessage = message;
});
print(message);
}
Scaffold.of(ctx).showSnackBar(
SnackBar(
content: Text(message),
backgroundColor: Theme.of(ctx).errorColor,
),
);
setState(() {
_isLoading = false;
});
} catch (error) {
print(error);
setState(() {
errorMessage = error.toString();
});
Scaffold.of(ctx).showSnackBar(
SnackBar(
content: Text(errorMessage),
backgroundColor: Colors.red,
),
);
setState(() {
_isLoading = false;
});
}
}

@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: AuthForm(
_submitAuthForm,
_isLoading,
),
),
);
}
}

If you find anything that could be improved please let me know, I would love to improve.💙

If this article has helped you a bit and found interesting please clap!👏


Feel free to connect with us:
And read more articles from FlutterDevs.com

FlutterDevs team of Flutter developers to build high-quality and functionally-rich apps. Hire flutter developer for your cross-platform Flutter mobile app project on an hourly or full-time basis as per your requirement! You can connect with us on Facebook, GitHub, Twitter, and LinkedIn for any flutter related queries.

We welcome feedback and hope that you share what you’re working on using #FlutterDevs. We truly enjoy seeing how you use Flutter to build beautiful, interactive web experiences!.


RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

- Advertisment -
Google search engine

Most Popular

Recent Comments