Search code examples
flutterfirebase-authentication

Flutter FirebaseAuth on web never persists user login


I am using Firebase auth on my Flutter web app.

During a debug session, I log a user in. This succeeds and Firebase returns a User object. After I close the debug session (I am debugging on chrome), and then start a new debug session, the user is never persisted.

I have recreated a minimal example app in it entirety.

With the below code here are the steps to repro...

  1. Open app for first time, it prints "Signed out"

  2. Press the login button, it prints "Signed in".

  3. End the debug session by closing chrome or stopping from vscode.

  4. Start a new debugging session in chrome, it prints "signed out", when expected would be "signed in".

     import 'package:flutter/material.dart';
     import 'package:firebase_core/firebase_core.dart';
     import 'package:firebase_auth/firebase_auth.dart';
    
     void main() {
       runApp(const MyApp());
     }
    
     class MyApp extends StatelessWidget {
       const MyApp({super.key});
    
       @override
       Widget build(BuildContext context) {
         return MaterialApp(title: 'Flutter Demo',home: const MyHomePage(),);
       }
     }
    
     class MyHomePage extends StatefulWidget {
       const MyHomePage({super.key});
    
       @override
       State<MyHomePage> createState() => _MyHomePageState();
     }
    
     class _MyHomePageState extends State<MyHomePage> {
       @override
       void initState() {
         super.initState();
         Future.sync(() async {
           await Firebase.initializeApp(
             options: const FirebaseOptions(
               // redacted firebase creds
             ),
           );
           FirebaseAuth.instance.authStateChanges().listen((user) {
             user == null ? print("signed out") : print("signed in");;
           });
         });
       }
    
       @override
       Widget build(BuildContext context) {
         return Center(
           child: ElevatedButton(
             onPressed: () async {
               FirebaseAuth.instance.signInWithEmailAndPassword(email: "[email protected]", password: "qwer1234");
             },
             child: const Text('Sign In'),
           )
         );
       }
     }
    

Solution

  • The issue likely stems from Chrome's debug sessions using a temporary profile that doesn't persist data.

    1. Configure Chrome to Use Persistent Storage

    Add a user data directory flag to your debug configuration: In launch.json (VS Code):

    {
      "version": "0.2.0",
      "configurations": [
        {
          "name": "Flutter: Chrome",
          "request": "launch",
          "type": "dart",
          "args": [
            "--user-data-dir=./chrome_profile"
          ]
        }
      ]
    }
    

    The --user-data-dir flag forces Chrome to use a persistent storage location between sessions, allowing Firebase's localStorage data to persist.

    1. Secondly, Check LocalStorage during debugging:

    Open Chrome DevTools (F12) Go to Application > Storage > Local Storage Verify if Firebase entries (like firebase:authUser:...) exist after login and persist after restart.

    1. Also try to test it with Production Mode. Build and serve your app to check if persistence works outside debug mode:
    flutter build web
    flutter run -d chrome --release
    
    1. If not works, then try this code for explicit persistence configuration:
    import 'package:flutter/material.dart';
    import 'package:firebase_core/firebase_core.dart';
    import 'package:firebase_auth/firebase_auth.dart';
    
    void main() {
      runApp(const MyApp());
    }
    
    class MyApp extends StatelessWidget {
      const MyApp({super.key});
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          home: const MyHomePage(),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      const MyHomePage({super.key});
    
      @override
      State<MyHomePage> createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      @override
      void initState() {
        super.initState();
        _initializeFirebase();
      }
    
      Future<void> _initializeFirebase() async {
        await Firebase.initializeApp(
          options: const FirebaseOptions(
            // Your Firebase config here
            apiKey: "AIza...",
            authDomain: "your-app.firebaseapp.com",
            projectId: "your-app",
            storageBucket: "your-app.appspot.com",
            messagingSenderId: "123...",
            appId: "1:123...:web:abc...",
          ),
        );
    
        // Explicitly set persistence
        await FirebaseAuth.instance.setPersistence(Persistence.LOCAL);
    
        // Listen to auth state
        FirebaseAuth.instance.authStateChanges().listen((user) {
          user == null ? print("signed out") : print("signed in");
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: Center(
            child: ElevatedButton(
              onPressed: () async {
                try {
                  await FirebaseAuth.instance.signInWithEmailAndPassword(
                    email: "[email protected]",
                    password: "qwer1234",
                  );
                } catch (e) {
                  print("Login error: $e");
                }
              },
              child: const Text('Sign In'),
            ),
          ),
        );
      }
    }