Skip to content

Commit

Permalink
fix(auth, web): fix currentUser being null when using emulator or nam…
Browse files Browse the repository at this point in the history
…ed instance (#10565)

* fix(auth, web): fix currentUser being null when using emulator or named instance

* fix(auth, web): fix currentUser being null when using emulator or named instance

* fix(auth, web): fix currentUser being null when using emulator or named instance
  • Loading branch information
Lyokone authored Mar 7, 2023
1 parent bc503e2 commit 11e8644
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 35 deletions.
42 changes: 20 additions & 22 deletions packages/firebase_auth/firebase_auth/example/lib/auth.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import 'dart:io';

import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_auth_example/main.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
Expand All @@ -14,8 +15,6 @@ import 'package:google_sign_in/google_sign_in.dart';

typedef OAuthSignIn = void Function();

final FirebaseAuth _auth = FirebaseAuth.instance;

// If set to true, the app will request notification permissions to use
// silent verification for SMS MFA instead of Recaptcha.
const withSilentVerificationSMSMFA = true;
Expand Down Expand Up @@ -91,7 +90,7 @@ class _AuthGateState extends State<AuthGate> {
void initState() {
super.initState();

if (withSilentVerificationSMSMFA) {
if (withSilentVerificationSMSMFA && !kIsWeb) {
FirebaseMessaging messaging = FirebaseMessaging.instance;
messaging.requestPermission();
}
Expand Down Expand Up @@ -371,7 +370,7 @@ class _AuthGateState extends State<AuthGate> {

if (email != null) {
try {
await _auth.sendPasswordResetEmail(email: email!);
await auth.sendPasswordResetEmail(email: email!);
ScaffoldSnackbar.of(context).show('Password reset email is sent');
} catch (e) {
ScaffoldSnackbar.of(context).show('Error resetting');
Expand All @@ -383,7 +382,7 @@ class _AuthGateState extends State<AuthGate> {
setIsLoading();

try {
await _auth.signInAnonymously();
await auth.signInAnonymously();
} on FirebaseAuthException catch (e) {
setState(() {
error = '${e.message}';
Expand Down Expand Up @@ -411,7 +410,6 @@ class _AuthGateState extends State<AuthGate> {
if (firstHint is! PhoneMultiFactorInfo) {
return;
}
final auth = FirebaseAuth.instance;
await auth.verifyPhoneNumber(
multiFactorSession: e.resolver.session,
multiFactorInfo: firstHint,
Expand Down Expand Up @@ -457,12 +455,12 @@ class _AuthGateState extends State<AuthGate> {
if (formKey.currentState?.validate() ?? false) {
setIsLoading();
if (mode == AuthMode.login) {
await _auth.signInWithEmailAndPassword(
await auth.signInWithEmailAndPassword(
email: emailController.text,
password: passwordController.text,
);
} else if (mode == AuthMode.register) {
await _auth.createUserWithEmailAndPassword(
await auth.createUserWithEmailAndPassword(
email: emailController.text,
password: passwordController.text,
);
Expand All @@ -480,14 +478,14 @@ class _AuthGateState extends State<AuthGate> {
} else {
if (kIsWeb) {
final confirmationResult =
await _auth.signInWithPhoneNumber(phoneController.text);
await auth.signInWithPhoneNumber(phoneController.text);
final smsCode = await getSmsCodeFromUser(context);

if (smsCode != null) {
await confirmationResult.confirm(smsCode);
}
} else {
await _auth.verifyPhoneNumber(
await auth.verifyPhoneNumber(
phoneNumber: phoneController.text,
verificationCompleted: (_) {},
verificationFailed: (e) {
Expand All @@ -507,7 +505,7 @@ class _AuthGateState extends State<AuthGate> {

try {
// Sign the user in (or link) with the credential
await _auth.signInWithCredential(credential);
await auth.signInWithCredential(credential);
} on FirebaseAuthException catch (e) {
setState(() {
error = e.message ?? '';
Expand Down Expand Up @@ -540,17 +538,17 @@ class _AuthGateState extends State<AuthGate> {
);

// Once signed in, return the UserCredential
await _auth.signInWithCredential(credential);
await auth.signInWithCredential(credential);
}
}

Future<void> _signInWithTwitter() async {
TwitterAuthProvider twitterProvider = TwitterAuthProvider();

if (kIsWeb) {
await _auth.signInWithPopup(twitterProvider);
await auth.signInWithPopup(twitterProvider);
} else {
await _auth.signInWithProvider(twitterProvider);
await auth.signInWithProvider(twitterProvider);
}
}

Expand All @@ -560,9 +558,9 @@ class _AuthGateState extends State<AuthGate> {

if (kIsWeb) {
// Once signed in, return the UserCredential
await _auth.signInWithPopup(appleProvider);
await auth.signInWithPopup(appleProvider);
} else {
await _auth.signInWithProvider(appleProvider);
await auth.signInWithProvider(appleProvider);
}
}

Expand All @@ -571,29 +569,29 @@ class _AuthGateState extends State<AuthGate> {

if (kIsWeb) {
// Once signed in, return the UserCredential
await _auth.signInWithPopup(yahooProvider);
await auth.signInWithPopup(yahooProvider);
} else {
await _auth.signInWithProvider(yahooProvider);
await auth.signInWithProvider(yahooProvider);
}
}

Future<void> _signInWithGitHub() async {
final githubProvider = GithubAuthProvider();

if (kIsWeb) {
await _auth.signInWithPopup(githubProvider);
await auth.signInWithPopup(githubProvider);
} else {
await _auth.signInWithProvider(githubProvider);
await auth.signInWithProvider(githubProvider);
}
}

Future<void> _signInWithMicrosoft() async {
final microsoftProvider = MicrosoftAuthProvider();

if (kIsWeb) {
await _auth.signInWithPopup(microsoftProvider);
await auth.signInWithPopup(microsoftProvider);
} else {
await _auth.signInWithProvider(microsoftProvider);
await auth.signInWithProvider(microsoftProvider);
}
}
}
Expand Down
11 changes: 8 additions & 3 deletions packages/firebase_auth/firebase_auth/example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,24 @@ import 'profile.dart';
/// See https://firebase.flutter.dev/docs/auth/start/#optional-prototype-and-test-with-firebase-local-emulator-suite
bool shouldUseFirebaseEmulator = false;

late final FirebaseApp app;
late final FirebaseAuth auth;

// Requires that the Firebase Auth emulator is running locally
// e.g via `melos run firebase:emulator`.
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
// We're using the manual installation on non-web platforms since Google sign in plugin doesn't yet support Dart initialization.
// See related issue: https://github.com/flutter/flutter/issues/96391

await Firebase.initializeApp(
// We store the app and auth to make testing with a named instance easier.
app = await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
auth = FirebaseAuth.instanceFor(app: app);

if (shouldUseFirebaseEmulator) {
await FirebaseAuth.instance.useAuthEmulator('localhost', 9099);
await auth.useAuthEmulator('localhost', 9099);
}

runApp(const AuthExampleApp());
Expand Down Expand Up @@ -73,7 +78,7 @@ class AuthExampleApp extends StatelessWidget {
? constraints.maxWidth / 2
: constraints.maxWidth,
child: StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
stream: auth.authStateChanges(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return const ProfilePage();
Expand Down
8 changes: 4 additions & 4 deletions packages/firebase_auth/firebase_auth/example/lib/profile.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import 'dart:developer';

import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_auth_example/main.dart';
import 'package:flutter/material.dart';
import 'package:google_sign_in/google_sign_in.dart';

Expand Down Expand Up @@ -36,12 +37,12 @@ class _ProfilePageState extends State<ProfilePage> {

@override
void initState() {
user = FirebaseAuth.instance.currentUser!;
user = auth.currentUser!;
controller = TextEditingController(text: user.displayName);

controller.addListener(_onNameChanged);

FirebaseAuth.instance.userChanges().listen((event) {
auth.userChanges().listen((event) {
if (event != null && mounted) {
setState(() {
user = event;
Expand Down Expand Up @@ -200,7 +201,6 @@ class _ProfilePageState extends State<ProfilePage> {
TextButton(
onPressed: () async {
final session = await user.multiFactor.getSession();
final auth = FirebaseAuth.instance;
await auth.verifyPhoneNumber(
multiFactorSession: session,
phoneNumber: phoneController.text,
Expand Down Expand Up @@ -306,7 +306,7 @@ class _ProfilePageState extends State<ProfilePage> {

/// Example code for sign out.
Future<void> _signOut() async {
await FirebaseAuth.instance.signOut();
await auth.signOut();
await GoogleSignIn().signOut();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
// found in the LICENSE file.

import 'dart:async';
import 'dart:html';

import 'package:firebase_auth_platform_interface/firebase_auth_platform_interface.dart';
import 'package:firebase_auth_web/src/firebase_auth_web_multi_factor.dart';
Expand All @@ -13,6 +14,7 @@ import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_core_web/firebase_core_web.dart';
import 'package:firebase_core_web/firebase_core_web_interop.dart'
as core_interop;
import 'package:flutter/foundation.dart';
import 'package:flutter_web_plugins/flutter_web_plugins.dart';

import 'src/firebase_auth_web_confirmation_result.dart';
Expand Down Expand Up @@ -89,8 +91,22 @@ class FirebaseAuthWeb extends FirebaseAuthPlatform {

/// Called by PluginRegistry to register this plugin for Flutter Web
static void registerWith(Registrar registrar) {
FirebaseCoreWeb.registerService('auth', () async {
await FirebaseAuthWeb.instance.delegate.onWaitInitState();
FirebaseCoreWeb.registerService('auth', (firebaseApp) async {
final authDelegate = auth_interop.getAuthInstance(firebaseApp);
// if localhost, and emulator was previously set in localStorage, use it
if (window.location.hostname == 'localhost' && kDebugMode) {
final String? emulatorOrigin =
window.sessionStorage['firebaseEmulatorOrigin'];

if (emulatorOrigin != null) {
authDelegate.useAuthEmulator(emulatorOrigin);
// ignore: avoid_print
print(
'Using previously configured Auth emulator at $emulatorOrigin \nTo switch back to production, restart your app with the emulator turned off.',
);
}
}
await authDelegate.onWaitInitState();
});
FirebaseAuthPlatform.instance = FirebaseAuthWeb.instance;
PhoneMultiFactorGeneratorPlatform.instance = PhoneMultiFactorGeneratorWeb();
Expand Down Expand Up @@ -434,10 +450,27 @@ class FirebaseAuthWeb extends FirebaseAuthPlatform {
@override
Future<void> useAuthEmulator(String host, int port) async {
try {
// Get current session storage value
final String? emulatorOrigin =
window.sessionStorage['firebaseEmulatorOrigin'];

// The generic platform interface is with host and port split to
// centralize logic between android/ios native, but web takes the
// origin as a single string
delegate.useAuthEmulator('http://$host:$port');
final String origin = 'http://$host:$port';

if (origin == emulatorOrigin) {
// If the origin is the same as the current one, do nothing
// The emulator was already started at the app start
return;
}

delegate.useAuthEmulator(origin);
// Save to session storage so that the emulator is used on refresh
// only in debug mode
if (kDebugMode) {
window.sessionStorage['firebaseEmulatorOrigin'] = origin;
}
} catch (e) {
final String code = (e as auth_interop.AuthError).code;
// this catches Firebase Error from web that occurs after hot reloading & hot restarting
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ class FirebaseWebService {
});
}

typedef EnsurePluginInitialized = Future<void> Function()?;
typedef EnsurePluginInitialized = Future<void> Function(
firebase.App firebaseApp,
)?;

/// The entry point for accessing Firebase.
///
Expand Down Expand Up @@ -302,11 +304,11 @@ class FirebaseCoreWeb extends FirebasePlatform {
_services.values.map((service) {
final ensureInitializedFunction = service.ensurePluginInitialized;

if (ensureInitializedFunction == null) {
if (ensureInitializedFunction == null || app == null) {
return Future.value();
}

return ensureInitializedFunction();
return ensureInitializedFunction(app);
}),
);

Expand Down

0 comments on commit 11e8644

Please sign in to comment.