Using Firebase as your Backend for your Flutter Mobile Applications(II)

Jesutoni Aderibigbe
7 min readApr 23, 2023

--

In our last tutorial, we tried syncing our Flutter mobile application with Firebase. Today, we will be moving forward by building a simple login and sign-up screen while using Firebase Authentication as our backend.

Are you ready?

Building a Sign-Up Screen

In your flutter project that was created in your first tutorial, follow these steps;

  • Create a new folder in your lib project folder named “Pages”. The reason for this is to promote clean and readable code.
  • Create a new file named “sign_up_page.dart”
  • Create a stateful widget by typing “stl”. You should have this;
import 'package:flutter/material.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'package:flutter/src/widgets/placeholder.dart';

class SignUp extends StatefulWidget {
const SignUp({super.key});

@override
State<SignUp> createState() => _SignUpState();
}

class _SignUpState extends State<SignUp> {
@override
Widget build(BuildContext context) {
return Scaffold();
}
}
  • In your scaffold, create the following fields for username, first name, last name, and password. You can customize it depending on your needs.
        body: GestureDetector(
child: Center(
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
height: 80,
width: 200,
child: TextFormField(
controller: name,
decoration: InputDecoration(
labelText: "Username",
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12.0)),
disabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12.0)),
),
),
),
const SizedBox(height: 70),
SizedBox(
height: 80,
width: 200,
child: TextFormField(
controller: firstname,
decoration: InputDecoration(
labelText: "First Name",
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12.0)),
disabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12.0)),
),
),
),
const SizedBox(height: 70),
SizedBox(
height: 80,
width: 200,
child: TextFormField(
controller: lastname,
decoration: InputDecoration(
labelText: "Last Name",
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12.0)),
disabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12.0)),
),
),
),
const SizedBox(height: 70),
SizedBox(
height: 80,
width: 200,
child: TextFormField(
autocorrect: true,
autovalidateMode: AutovalidateMode.always,
controller: password,
validator: (value) {
if (value!.length < 6) {
return "Password can't be less than six characters";
}
},
decoration: InputDecoration(
labelText: "Password",
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12.0)),
disabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12.0)),
),
),
),
SizedBox(height: 30),
Center(
child: GestureDetector(
onTap: () {
signUp();
},
child: Container(
height: 50,
width: 100,
child: const Center(
child: Text(
"SIGN UP",
style: TextStyle(color: Colors.white),
)),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12.0),
color: Colors.black,
shape: BoxShape.rectangle),
),
),
)
],
),
),
),
)

You would notice that I added controllers; The essence of this in Flutter, TextEditingController is a class that allows you to control and manipulate the text of a TextField widget. When you create an instance of TextEditingController for a TextField, it allows you to retrieve the current value of the TextField or set a new value programmatically.

The code TextEditingController name = TextEditingController(); creates a new instance of TextEditingController and assigns it to the variable name. Similarly, TextEditingController password = TextEditingController(); creates a new instance of TextEditingController and assigns it to the variable password.

These TextEditingController objects can then be used to manipulate the text entered by the user in the corresponding TextField widgets. For example, you could retrieve the text entered by the user in the name field by calling name.text, or you could set the text of the password field programmatically by calling password.text = "new password".

Overall, the purpose of creating TextEditingController objects are to provide a way to access and modify the text entered by the user in a TextField widget.

  • Create a signup button that the user can click and authenticates the user. You can do that by;
 Center(
child: GestureDetector(
onTap: () {

},
child: Container(
height: 50,
width: 100,
child: const Center(
child: Text(
"SIGN UP",
style: TextStyle(color: Colors.white),
)),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12.0),
color: Colors.black,
shape: BoxShape.rectangle),
),
),
)

We are done with the UI. You should have something like this;

You can beautify it to suit your taste.

Let’s move to the backend…

You have to first import Firebase auth to your Flutter project and instantiate it to use the authentication throughout the app. You can do this by;

  FirebaseAuth auth = FirebaseAuth.instance;

Having done this, we can then sign up the user with Firebase. To do this all you need is to type;

await auth.createUserWithEmailAndPassword();

It takes a required String email and password

void signUp() async {
try {
await auth.createUserWithEmailAndPassword(
email: name.text.trim(), password: password.text.trim());
const Center(
child: CircularProgressIndicator(
color: Colors.black,
));
Navigator.push(
context, MaterialPageRoute(builder: (_) => WelcomePage()));
print("Account created for user with ${name.text}");
} on FirebaseAuthException catch (e) {
if (e.code == 'weak-password') {
print('The password provided is too weak.');
} else if (e.code == 'email-already-in-use') {
print('The account already exists for that email.');
} else {
showDialog(
context: context,
builder: (_) => AlertDialog(
title: const Text('Error'),
content: const Text('There was an error signing up this user.'),
actions: [
TextButton(
child: const Text('OK'),
onPressed: () => Navigator.pop(context),
),
],
),
);
print('Error during signup: $e');
}
} catch (e) {
showDialog(
context: context,
builder: (_) => AlertDialog(
title: const Text('Error'),
content: const Text('There was an error signing up this user.'),
actions: [
TextButton(
child: const Text('OK'),
onPressed: () => Navigator.pop(context),
),
],
),
);
print('Error during signup: $e');
}
}

Here, we created a dart function that signs up a user. It is placed in a try-catch block to prevent your app from failing whenever there is an error in your codes.

  • After this is done, call this function in your sign-up button. It should be like this;
 Center(
child: GestureDetector(
onTap: () {
signUp();
},
child: Container(
height: 50,
width: 100,
child: const Center(
child: Text(
"SIGN UP",
style: TextStyle(color: Colors.white),
)),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12.0),
color: Colors.black,
shape: BoxShape.rectangle),
),
),
)
  • Thus, if you could sign up, it takes you to the welcome page or else it displays a dialog box that an error has happened

Building a Login Screen

In your flutter project that was created in your first tutorial, follow these steps;

  • Create a new folder in your lib project folder named “Pages”. The reason for this is to promote clean and readable code.
  • Create a new file named “loginpage.dart”
  • You can write the following code to build a login page;
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'package:flutter/src/widgets/placeholder.dart';

class LoginPage extends StatefulWidget {
const LoginPage({super.key});

@override
State<LoginPage> createState() => _MyWidgetState();
}

class _MyWidgetState extends State<LoginPage> {
FirebaseAuth auth = FirebaseAuth.instance;

@override
Widget build(BuildContext context) {
TextEditingController name = TextEditingController();
TextEditingController password = TextEditingController();

void login() async {
try {
await auth.signInWithEmailAndPassword(
email: name.text.trim(), password: password.text.trim());
const Center(
child: CircularProgressIndicator(
color: Colors.black,
));
print("Account created for user with ${name.text}");
} 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.');
} else {
print('Error during login: $e');
}
} catch (e) {
print('Error during signup: $e');
}
}

return Scaffold(
appBar: AppBar(
title: Text("Login Page"),
),
body: GestureDetector(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
height: 80,
width: 200,
child: TextFormField(
controller: name,
decoration: InputDecoration(
labelText: "Username",
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12.0)),
disabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12.0)),
),
),
),
const SizedBox(height: 70),
SizedBox(
height: 80,
width: 200,
child: TextFormField(
autocorrect: true,
autovalidateMode: AutovalidateMode.always,
controller: password,
validator: (value) {
if (value!.length < 6) {
return "Password can't be less than six characters";
}
},
decoration: InputDecoration(
labelText: "Password",
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12.0)),
disabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12.0)),
),
),
),
SizedBox(height: 30),
Center(
child: GestureDetector(
onTap: () {
login();
},
child: Container(
height: 50,
width: 100,
child: const Center(
child: Text(
"LOG IN",
style: TextStyle(color: Colors.white),
)),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12.0),
color: Colors.black,
shape: BoxShape.rectangle),
),
),
)
],
),
),
));
}
}

Let me explain this code to you;

Firstly, I created a stateful widget named “Login Page”

Having done this, I created an instance of the Firebase Auth to handle authentication anywhere on my screen.

You would also see this too;

  TextEditingController name = TextEditingController();
TextEditingController password = TextEditingController();

I also created a dart function called “Login” which basically handles my sign-in method with Firebase. It is placed in a try-catch block to prevent your app from crashing every time it is being used and an error happens.

Then for this;

 return Scaffold(
appBar: AppBar(
title: Text("Login Page"),
),
body: GestureDetector(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
height: 80,
width: 200,
child: TextFormField(
controller: name,
decoration: InputDecoration(
labelText: "Username",
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12.0)),
disabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12.0)),
),
),
),
const SizedBox(height: 70),
SizedBox(
height: 80,
width: 200,
child: TextFormField(
autocorrect: true,
autovalidateMode: AutovalidateMode.always,
controller: password,
validator: (value) {
if (value!.length < 6) {
return "Password can't be less than six characters";
}
},
decoration: InputDecoration(
labelText: "Password",
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12.0)),
disabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12.0)),
),
),
),
SizedBox(height: 30),
Center(
child: GestureDetector(
onTap: () {
login();
},
child: Container(
height: 50,
width: 100,
child: const Center(
child: Text(
"LOG IN",
style: TextStyle(color: Colors.white),
)),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12.0),
color: Colors.black,
shape: BoxShape.rectangle),
),
),
)
],
),
),
));

This is a simple scaffold that has two text-form fields with two controllers respectively placed in a column. You can beautify the UI to suit your taste.

With this, you have been able to successfully create a back-end system for your sign-up and login page.

You can check the full code from my GitHub repository. I will be updating the code every time I write another series on Firebase. We will be building a full-stack application by the time we are done with this series.

In our next tutorial, we will be working with a validation system, Cloud-firestore, and possibly Firebase Storage.

See you there!

--

--