In this flutter firebase tutorial, we will learn flutter firebase phone number authentication and will sent OTP verification SMS to verify.
In this video, we’ll be learning how to create a Flutter Firebase phone number OTP authentication. This will allow us to secure our phone numbers with an OTP verification mechanism.
Flutter is a new mobile development framework that has been gaining a lot of popularity lately. In this video, we’ll be using Flutter to create a Firebase phone number OTP authentication.
So whether you’re a beginner or an experienced developer, be sure to check out this video and learn how to create a Flutter Firebase phone number OTP authentication!
Go to the project folder in the terminal.
Mac keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android
Windows keytool -list -v -keystore "\.android\debug.keystore" -alias androiddebugkey -storepass android -keypass android
Linux keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android
OTHER USEFUL LINKS
- Install Android Studio
- Install Flutter
- Create a new flutter app
- Create Folder Structure
- Setup Theme in Flutter for Light & Dark Mode
This is the tutorial of our Flutter Login App Series.
Watch Youtube tutorial
import 'package:firebase_auth/firebase_auth.dart';
import 'package:get/get.dart';
import 'package:login_flutter_app/src/features/authentication/screens/welcome/welcome_screen.dart';
import 'package:login_flutter_app/src/features/core/screens/dashboard/dashboard.dart';import 'exceptions/login_with_email_and_pssword_failure.dart';
import 'exceptions/signup_email_password_failure.dart';class AuthenticationRepository extends GetxController {
static AuthenticationRepository get instance => Get.find();//Variables
final _auth = FirebaseAuth.instance;
late final Rx<User?> firebaseUser;//Will be load when app launches this func will be called and set the firebaseUser state
@override
void onReady() {
firebaseUser = Rx<User?>(_auth.currentUser);
firebaseUser.bindStream(_auth.userChanges());
ever(firebaseUser, _setInitialScreen);
}/// If we are setting initial screen from here
/// then in the main.dart => App() add CircularProgressIndicator()
_setInitialScreen(User? user) {
user == null ? Get.offAll(() => const WelcomeScreen()) : Get.offAll(() => const Dashboard());
}//FUNC
Future<String?> createUserWithEmailAndPassword(String email, String password) async {
try {
await _auth.createUserWithEmailAndPassword(email: email, password: password);
firebaseUser.value != null ? Get.offAll(() => const Dashboard()) : Get.to(() => const WelcomeScreen());
} on FirebaseAuthException catch (e) {
final ex = SignUpWithEmailAndPasswordFailure.code(e.code);
return ex.message;
} catch (_) {
const ex = SignUpWithEmailAndPasswordFailure();
return ex.message;
}
return null;
}Future<String?> loginWithEmailAndPassword(String email, String password) async {
try {
await _auth.signInWithEmailAndPassword(email: email, password: password);
} on FirebaseAuthException catch (e) {
final ex = LogInWithEmailAndPasswordFailure.fromCode(e.code);
return ex.message;
} catch (_) {
const ex = LogInWithEmailAndPasswordFailure();
return ex.message;
}
return null;
}Future<void> logout() async => await _auth.signOut();
}
class SignUpFormWidget extends StatelessWidget {
const SignUpFormWidget({
Key? key,
}) : super(key: key);@override
Widget build(BuildContext context) {
final controller = Get.put(SignUpController());
final formKey = GlobalKey<FormState>();return Container(
padding: const EdgeInsets.symmetric(vertical: tFormHeight - 10),
child: Form(
key: formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextFormField(
controller: controller.fullName,
decoration: const InputDecoration(label: Text(tFullName), prefixIcon: Icon(Icons.person_outline_rounded)),
),
const SizedBox(height: tFormHeight - 20),
TextFormField(
controller: controller.email,
decoration: const InputDecoration(label: Text(tEmail), prefixIcon: Icon(Icons.email_outlined)),
),
const SizedBox(height: tFormHeight - 20),
TextFormField(
controller: controller.phoneNo,
decoration: const InputDecoration(label: Text(tPhoneNo), prefixIcon: Icon(Icons.numbers)),
),
const SizedBox(height: tFormHeight - 20),
TextFormField(
controller: controller.password,
decoration: const InputDecoration(label: Text(tPassword), prefixIcon: Icon(Icons.fingerprint)),
),
const SizedBox(height: tFormHeight - 10),
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: () {
if(formKey.currentState!.validate()) {
// SignUpController.instance.registerUser(controller.email.text.trim(), controller.password.text.trim());
SignUpController.instance.phoneAuthentication(controller.phoneNo.text.trim());
Get.to(() => const OTPScreen());
}
},
child: Text(tSignup.toUpperCase()),
),
)
],
),
),
);
}
}
import 'package:flutter/material.dart';
import 'package:get/get.dart';import '../../../repository/authentication_repository/authentication_repository.dart';
class SignUpController extends GetxController {
static SignUpController get instance => Get.find();//TextField Controllers to get data from TextFields
final email = TextEditingController();
final password = TextEditingController();
final fullName = TextEditingController();
final phoneNo = TextEditingController();/// This func will be used to register user with [EMAIL] & [Password]
void registerUser(String email, String password) {
String? error = AuthenticationRepository.instance.createUserWithEmailAndPassword(email, password) as String?;
if (error != null) {
Get.showSnackbar(GetSnackBar(message: error.toString()));
}
}//Get phoneNo from user (Screen) and pass it to Auth Repository for Firebase Authentication
void phoneAuthentication(String phoneNo) {
AuthenticationRepository.instance.phoneAuthentication(phoneNo);
}
}
class OTPController extends GetxController {
static OTPController get instance => Get.find();void verifyOTP(String otp) async {
var isVerified = await AuthenticationRepository.instance.verifyOTP(otp);
isVerified ? Get.offAll(const Dashboard()) : Get.back();
}}
6 – Clean Code
To keep code clean, manageable, and readable we use State Management. Therefore we are using GETX State management to follow the seperation of concern principle.
Hence, we have design in Screens Folder and it has nothing to do with backend logic. Backend logic only deals with logic of the screen and not performing Database Queries. Authentication and User Repositories are only dealing with Firebase authentication and Firebase Firestore database.