import 'package:firebase_auth/firebase_auth.dart' hide PhoneAuthProvider, EmailAuthProvider;
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:firebase_ui_localizations/firebase_ui_localizations.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'firebase_options.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
FirebaseUIAuth.configureProviders([
EmailAuthProvider(),
PhoneAuthProvider(),
]);
runApp(const FirebaseAuthUIExample());
}
class LabelOverrides extends DefaultLocalizations {
const LabelOverrides();
@override
String get emailInputLabel => 'Enter your email';
}
class FirebaseAuthUIExample extends StatelessWidget {
const FirebaseAuthUIExample({super.key});
String get initialRoute {
final user = FirebaseAuth.instance.currentUser;
return switch (user) {
null => '/',
_ => '/profile',
};
}
@override
Widget build(BuildContext context) {
final mfaAction = AuthStateChangeAction<MFARequired>(
(context, state) async {
final nav = Navigator.of(context);
await startMFAVerification(
resolver: state.resolver,
context: context,
);
nav.pushReplacementNamed('/profile');
},
);
return MaterialApp(
initialRoute: initialRoute,
routes: {
'/': (context) {
return SignInScreen(
actions: [
VerifyPhoneAction((context, _) {
Navigator.pushNamed(context, '/phone');
}),
mfaAction,
EmailLinkSignInAction((context) {
Navigator.pushReplacementNamed(context, '/email-link-sign-in');
}),
],
);
},
'/phone': (context) {
return PhoneInputScreen(
actions: [
SMSCodeRequestedAction((context, action, flowKey, phone) {
Navigator.of(context).pushReplacementNamed(
'/sms',
arguments: {
'action': action,
'flowKey': flowKey,
'phone': phone,
},
);
}),
],
);
},
'/sms': (context) {
final arguments = ModalRoute.of(context)?.settings.arguments as Map<String, dynamic>?;
return SMSCodeInputScreen(
actions: [
AuthStateChangeAction<SignedIn>((context, state) {
Navigator.of(context).pushReplacementNamed('/profile');
})
],
flowKey: arguments?['flowKey'],
action: arguments?['action'],
);
},
'/profile': (context) {
final platform = Theme.of(context).platform;
return ProfileScreen(
actions: [
SignedOutAction((context) {
Navigator.pushReplacementNamed(context, '/');
}),
mfaAction,
],
showMFATile: kIsWeb || platform == TargetPlatform.iOS || platform == TargetPlatform.android,
showUnlinkConfirmationDialog: true,
showDeleteConfirmationDialog: true,
);
},
},
title: 'Firebase UI demo',
debugShowCheckedModeBanner: false,
locale: const Locale('ar', 'SA'),
supportedLocales: [const Locale('ar', 'SA')],
localizationsDelegates: [
FirebaseUILocalizations.withDefaultOverrides(const LabelOverrides()),
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
FirebaseUILocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
);
}
}
Is there an existing issue for this?
What plugin is this bug for?
Firebase UI Auth
What platform(s) does this bug affect?
Android, iOS
List of dependencies used.
flutter pub deps -s list
dev dependencies:
transitive dependencies:
Steps to reproduce
code sample to reproduce bug
the OTP verification starts and the user gets signed in.
Actual Behavior
sometimes the verification does not start (blocked by something? I am not certain) and another click (sometimes multiple clicks) on verify button is required to verify OTP. in other instances, I have to go back to main login page and retry entering the phone number and request another OTP. I notice that this happens when the app is launched fresh and not when signed out and then trying to sign in again.
Additional Information
I used this with a test phone number that was added to firebase authentication. When I try the same with a real phone number I end up receiving multiple SMS messages from Firebase. This makes the auth costs almost double for my project.

Here is a screen recording for the issue. in the video you notice the first sign in does not pick the OTP confirm button click and I had to click verify. In the second attempt (in the same screen recording) the OTP confirm button works right away.
https://github.com/firebase/FirebaseUI-Flutter/assets/12709757/c6508b8c-9100-4f1e-9ad4-792811ffbb8d