authController function

  1. @Riverpod(keepAlive: true)
Stream<UserModel> authController(
  1. dynamic ref
)

A provider for the UserModel stream.

This provider is used to provide the UserModel stream to the rest of the application. It is used to determine the user's authentication state. Any changes to the user's authentication state will be reflected in the stream, and some side effects will be triggered.

Implementation

@Riverpod(keepAlive: true)
Stream<UserModel> authController(AuthControllerRef ref) {
  return ref
      .watch(authServiceProvider)
      .authStateChanges()
      .asyncMap<UserModel>((user) async {
    if (user == null || user.displayName == null) {
      return UserModel.none();
    }

    // There is a user
    final hasInternet = ref.read(isConnectedProvider);
    final hasApprovedLogin =
        ref.read(sharedPreferencesProvider).getBool('hasApprovedLogin') ??
            false;

    if (!hasInternet && !hasApprovedLogin) {
      // No internet and no recent login: user needs to log in again.
      return UserModel.none();
    }

    if (!hasInternet) {
      // No internet but recent login. Enter the app without admin rights.
      return UserModel.fromUserAndClaims(
        user,
        CustomClaimsModel.fromJson({'admin': false, 'approved': true}),
      );
    }

    // If there is internet, check the claims
    final claims = (await user.getIdTokenResult()).claims!;
    final isApproved = claims['approved'] == true;

    if (user.emailVerified && isApproved) {
      // The user is approved and the email is verified.
      ref.read(sharedPreferencesProvider).setBool('hasApprovedLogin', true);
      return UserModel.fromUserAndClaims(
        user,
        CustomClaimsModel.fromJson(claims),
      );
    }

    // There is a user, but the email is not verified or the user is
    // not yet approved.
    ref.read(sharedPreferencesProvider).setBool('hasApprovedLogin', false);
    return UserModel.none();
  });
}