dazza5000
dazza5000

Reputation: 7618

Firebase Authentication is not persisted on Flutter Web

I am using Firebase Authentication on my Flutter Web app, but the session is not persisted during refresh.

This is the package I am using.

https://pub.dev/packages/firebase

This is how I am authenticating with Firebase

  static Future<User> handleSignInEmail(String email, String password) async {
    await init();

    final UserCredential userCredential =
        await auth().signInWithEmailAndPassword(email.trim(), password);

    assert(userCredential.user != null);
    assert(await userCredential.user.getIdToken() != null);

    final User currentUser = await userCredential.user;
    assert(userCredential.user.uid == currentUser.uid);

    print('signInEmail succeeded: $userCredential.user');

    return userCredential.user;
  }

If I refresh the page and call the following method, the user that is returned is null:

  static Future<User> getFirebaseUser() async {
    await init();
    return await auth().currentUser;
  }

A similar implementation using Flutter Mobile works as expected. What am I missing on the Flutter Web implementation?

Upvotes: 20

Views: 7064

Answers (4)

Katia
Katia

Reputation: 11

I'm using Flutter 3.0.5 and firebase_auth 3.6.4 and that's the only way I could make it work for web (Chrome):

class HomePage extends StatefulWidget {
  const HomePage();

  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  User? currentUser;
  late StreamSubscription<User?> userSubscription;

  @override
  void initState() {
    super.initState();
    userSubscription = FirebaseAuth.instance.authStateChanges().listen((user) {
      if (user != null) {
        setState(() {
          currentUser = user;
        });
      }
    });
  }

  @override
  void dispose() {
    userSubscription.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return currentUser != null
        ? Text('User is logged in')
        : Text('User is not logged in');
  }
}

As I understand, you need to wait until FirebaseAuth.instance.authStateChanges() returns non null value, but in the the beginning it returns null because there's something that still initializes in the background. Same goes for FirebaseAuth.instance.currentUser, it will be null until some point, so if you check it immediately, you'll be stuck in unauthorized state unless you recheck it later somehow.

Upvotes: 1

Gowtham P
Gowtham P

Reputation: 51

Extension of https://stackoverflow.com/a/58158636

In the new library version, onAuthStateChanged getter is not available. Instead of that use authStateChanges().

User firebaseUser = await FirebaseAuth.instance.currentUser;
  if (firebaseUser == null) {
    firebaseUser = await FirebaseAuth.instance.authStateChanges().first;
  }

https://pub.dev/documentation/firebase_auth/latest/firebase_auth/FirebaseAuth/authStateChanges.html

Upvotes: 5

JAY MEHTA
JAY MEHTA

Reputation: 89

Firebase Dart Package

Import this pub and check the OS wherever auth is used

import 'package:firebase/firebase.dart' as firebase;
import 'package:firebase_auth/firebase_auth.dart';

if(Platform.isIOS || Platform.isAndroid) {
    FirebaseAuth.instance.createUserWithEmailAndPassword(email: email, password: password).then(() {
        //do something
    });
} else {
    firebase.auth().createUserWithEmailAndPassword(email, password).then(() {
        //do something
    });
}

Upvotes: 2

Gedeon Gaal
Gedeon Gaal

Reputation: 306

Login happens automatically and it is handled by Firebase, however in async way. More details can be found in the official documentation:

https://firebase.google.com/docs/auth/web/auth-state-persistence

The trick is very simple. You need to wait for the first state change.

  static Future<User> getFirebaseUser() async {
    await init();
    //return await auth().currentUser;
    return await auth().onAuthStateChanged.first;
  }

It returns null if there is no signed-in user: https://firebase.google.com/docs/reference/js/firebase.auth.Auth.html#onauthstatechanged

My firebase version:

firebase: 5.0.4 #https://pub.dartlang.org/packages/firebase

I wrote this implementation which works on both mobile and web:

  static Future<FirebaseUser> getFirebaseUser() async {
    FirebaseUser firebaseUser = await FirebaseAuth.instance.currentUser();
    if (firebaseUser == null) {
      firebaseUser = await FirebaseAuth.instance.onAuthStateChanged.first;
    }
    return firebaseUser;
  }

Upvotes: 29

Related Questions