flutterauthentication

Flutter: how to check if user is logged in by using flutter_secure_storage


I have this code for flutter_secure_storage:

import 'package:flutter_secure_storage/flutter_secure_storage.dart';

class SecureStorage {
  final FlutterSecureStorage storage = const FlutterSecureStorage();

  writeSecureData(String key, String value) async {
    await storage.write(key: key, value: value);
  }

  Future<String> readSecureData(String key) async {
    String value = await storage.read(key: key) ?? 'NULL';
    return value;
  }

  deleteSecureData(String key) async {
    await storage.delete(key: key);
  }
}

I want to use the read method for deciding if user is logged in (and then the secure storage has his email):

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      localizationsDelegates: context.localizationDelegates,
      supportedLocales: context.supportedLocales,
      locale: context.locale,
      debugShowCheckedModeBanner: false,
      home: SecureStorage().readSecureData('keyUserEmail') == 'NULL'
          ? const Login()
          : MainPage(),
    );
  }
}

But is doesn't work and the app always begin at MainPage().

What am I doing wrong?

Thanks!


Solution

  • The problem with your code is that the readSecureData() method is asynchronous, but you are using it in a synchronous context. This means that the if statement is evaluating before the readSecureData() method has a chance to return a value.

    To fix this, you can use a FutureBuilder widget to wrap your if statement. This will ensure that the if statement is only evaluated after the readSecureData() method has returned a value.

    Here is an example of how to do this:

    import 'package:flutter/material.dart';
    import 'package:flutter_secure_storage/flutter_secure_storage.dart';
    
    class SecureStorage {
      final FlutterSecureStorage storage = const FlutterSecureStorage();
    
      writeSecureData(String key, String value) async {
        await storage.write(key: key, value: value);
      }
    
      Future<String> readSecureData(String key) async {
        String value = await storage.read(key: key) ?? 'NULL';
        return value;
      }
    
      deleteSecureData(String key) async {
        await storage.delete(key: key);
      }
    }
    
    class MyApp extends StatelessWidget {
      const MyApp({super.key});
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          localizationsDelegates: context.localizationDelegates,
          supportedLocales: context.supportedLocales,
          locale: context.locale,
          debugShowCheckedModeBanner: false,
          home: FutureBuilder(
            future: SecureStorage().readSecureData('keyUserEmail'),
            builder: (context, snapshot) {
              if (snapshot.hasData && snapshot.data != 'NULL') {
                return const MainPage();
              } else {
                return const Login();
              }
            },
          ),
        );
      }
    }
    

    With this code, the if statement will only evaluate after the readSecureData() method has returned a value. If the user has logged in and the secure storage has their email, the app will start at the MainPage(). Otherwise, the app will start at the Login().