Reputation: 7618
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
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
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
Reputation: 89
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
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