How to detect if otp is autofilled in flutter or not? - flutter

In Flutter Application, I have otp screen on which there's a login button. After the otp is automatically filled, user clicks login and a loader appears and user is logged in. But what if user clicks login before the otp is filled? I want to handle this situation. What should i do in this?

Most probably you should be having a controller for the otp field. On button click check if the otp controller is empty or incomplete. If not then do further execution. Else sure message otp is incomplete.
onTap :(){
if(otpController.text.length == 4)
{
//Process further
}
else{
//Otp isn't right
}
}

You can use Try - catch to check if credentials are correct.
try {
PhoneAuthCredential credential = PhoneAuthProvider.credential(
verificationId: verificationId,
smsCode: codeController.text.trim(),
);
UserCredential userCredential = await
_auth.signInWithCredential(credential);
}on FirebaseAuthException catch (e){
Print(e.toString());
}

if you using firebase, if otp automatically filled, that make your app authenticated. user don't need to press that button at all,your app listen to authStateChanges() and should update ui, and i assume your entire app is listen to auth state. if not, try to management that auth state in your app, using streambuilder, changenotifier, bloc management,etc. your choice.
if otp isn't there let say the user has 2 phone, and otp go in on another phone, then user should fill it manually.

Most probably you should be having a controller for the otp field. On button click check if the otp controller is empty or incomplete. If not then do further execution. Else sure message otp is incomplete.
onTap :(){
if(otpController.text.isNotEmpty || otpController.text != "")
{
//Process further
}
else{
//Otp isn't right
}
}

Related

Flutter Firebase OTP verification fails even though both sent and entered OTP are the same

I am trying to implement OTP verification in my Flutter app using Firebase, but I am facing an issue where the verification fails even though both the sent and entered OTP are the same.
I am using the following function to verify the OTP:
void verifyOtp({
required BuildContext context,
required String verificationId,
required String userOtp,
required Function onSuccess,
}) async {
_isLoading = true;
notifyListeners();
try {
PhoneAuthCredential creds = PhoneAuthProvider.credential(
verificationId: verificationId, smsCode: userOtp);
User? user = (await _firebaseAuth.signInWithCredential(creds)).user!;
print('signwithcredential passed');
if (user != null) {
_uid = user.uid;
onSuccess();
}
} on FirebaseAuthException catch (e) {
print('failed Userotp: $userOtp');
showSnackBar(context, e.message.toString());
_isLoading = false;
notifyListeners();
}
}
The error I am getting is "FirebaseAuthException: sms code has expired please resend the verification code to verify again."
I am new to Flutter and Firebase, so any help in fixing this problem would be greatly appreciated.
Here are couple of things I have found maybe they will work:
Check the Firebase Console to ensure that the phone number being verified is correctly set up and that the SMS code is being sent to the right number.
Make sure that the phone number is being passed in the correct format.
FirebaseAuthException is being caught correctly. Make sure the message inside the catch block is being logged or displayed to the user.
Ensure that the dependencies and packages are correctly installed and imported.
The solution is itself an error you are getting. You have to enter the code before it expire. Try to verify the otp as soon as you get the code as it's saying "I/flutter ( 9598): error on firebaseAuthexception: [firebase_auth/session-expired] The sms code has expired. Please re-send the verification code to try again. ".

Why am I not getting a password reset email from the Firebase service?

I am trying to implement a password reset function that incorporates a SnackBar to display either success or error messages. The code shown below produces both the success message and the various error messages, as appropriate - but I never receive the password reset email from the Firebase service. I'm not sure if it's a Firebase setup issue or an issue with the code.
Future resetPassword() async {
try {
await FirebaseAuth.instance
.sendPasswordResetEmail(email: _emailController.text.trim());
_showSnackBar('Password reset link sent');
} on FirebaseAuthException catch (e) {
_showSnackBar(e.message.toString());
return;
}
}
Future<void> _showSnackBar(String msg) async {
final snackBar = SnackBar(
content: Text(msg),
);
ScaffoldMessenger.of(context).showSnackBar(snackBar);
}
Disregard. Code seems to work fine - problem was either with Firebase Auth service or my internet service provider last night. All good now.
Make sure to check your spam, because if did not add authorize rules in firebase then the reset link goes in spam mail.
.

How to determine which provider the user logged in with

I am using multiple Firebase sign in methods in my app (Facebook, Google, Phone, etc). But once the user is logged in, I am unable to determine which provider was used to sign in.
I tried below(very close to the recommended solution. But does not work):
_auth.currentUser().providerData[0].providerId
I expect it to return something like "google.com" or "facebook.com"
Instead it returns "firebase"
I cant find any other solution where it clearly lets us determine if a google or facebook sign in was used. All solutions in the forum iOS specific or for web. Can't find anything flutter specific. Appreciate any help in advance.
I checked and _auth.currentUser().providerData[0].providerId does provide "google.com" or "facebook.com"
Not sure at what point it showed me "firebase". Will post to this if I figure this out
You can use the following code :
#override
Future<void> signOut() async {
final FirebaseAuth _auth = FirebaseAuth.instance;
try {
final _providerData = _auth.currentUser!.providerData;
if (_providerData.isNotEmpty) {
if (_providerData[0]
.providerId
.toLowerCase()
.contains('google')) {
await GoogleSignIn().signOut(); // google signOut
} else if (_providerData[0]
.providerId
.toLowerCase()
.contains('facebook')) {
await FacebookAuth.instance.login(); // facebook signOut
}
}
await _auth.signOut(); // firebase signOut
} catch (e) {
print(e);
}
}
I am not sure about facebook since I have never implemented login with facebook, but for Google, you may be able to do something like this.
You probably have a statement similar to GoogleSignInAccount googleUser = await _googleSignIn.signIn(). Why not check if google User is null or not once the user is signed in or on auth change? This will let you know if the user signed in with google.
Similar functionality for facebook should be possible but I just don't know if it is the same.
If googleUser != null then google was used.
If say facebookUser != null then facebook was used,
Then if googleUser is null and say facebookUser is null it was email.
Maybe this is helpful, maybe not, but it is just what I could think of right now.

Conditional bottom navigation bar

I have bottom navigation bar which consist of 5 icon which will redirect to 5 screen correspondingly.
The fifth icon is Account screen so when no session it must redirect to Login screen and then load the Account screen. But after login when user tap the Account icon just redirect to Account screen.
How to achieve this? How can I use if condition to determine which layout to load? Error says missing identifier expexted ')'
You can easily achieve this with by passing an async function for the onPressed of Account icon. Your async function would look something like.
Example:
//On Home Page, for account icon pressed
Future<void> checkCredsAndNavigate(){
bool loggedIn = _checkIfLoggedIn(); // this might be a function that gets status of user login, you can fetch from prefs, state, etc.
if(!loggedIn){
var data = await Navigator.of(context).pushNamed('YOUR_LOGIN_ROUTE_NAME');
if(data == null){ // Check for data, will be null when user cancels login
return;
}
}
Navigator.of(context).pushNamed('YOUR_ACCOUNT_ROUTE_NAME');
}
//On Login page,
// On successful login call
Navigator.of(context).pop(data); // this data can be anything like user id, or just a boolean indicating successful login,etc.
//To cancel login, call
Navigator.of(context).pop();
Hope this helps!

How to properly implement Logout with firebase on flutter

It sounds stupid but I cant really properly logout of my app and that is because I use multiple FirebaseAnimatedList and route on my MaterialApp
routes: <String,WidgetBuilder>{
'/StartAppPage':(BuildContext context)=>new StartAppPage(),
'/LoginPage':(BuildContext context)=> new LoginPage(),
'/HomePage':(BuildContext context)=> new HomePage)
},
So the app checks for use and routes to HomePage or Login based on is there is a user or not.
My Home page has a FirebaseAnimatedList and
on my Home page there is a Logout button that do this
await googleSignIn.signOut();
await FirebaseAuth.instance.signOut();
await FirebaseDatabase.instance.goOffline();
return Navigator.pushReplacementNamed(context, '/StartApp');
to HomePage and logout the user.
But when the other user login again the List shows data of the old user and the list is usable messing my Database
How can I properly implement this and the setPersistance is off or on makes no difference
Solution: Keep a single instance of your firebase user through the app. I recommend a global variable
After signing out, what you can consider doing here is check on the current screen if the user is authenticated or not. If the user is still logged-in, display the data. If not, then navigate to a Login screen.
FirebaseAuth.instance
.idTokenChanges()
.listen((User? user) {
if (user == null) {
debugPrint('User is currently signed out!');
// TODO: navigate to Login screen?
} else {
debugPrint('User is signed in!');
// TODO: display data
}
});