FirebaseAuthState constructor
FirebaseAuthState(
- FirebaseAuthAppModule authModule,
- User? _currentFbUser,
- UserDetails? currentProfile, {
- required Stream<
ErrorStack> appErrors,
Implementation
FirebaseAuthState(
this.authModule, this._currentFbUser, UserDetails? currentProfile,
{required Stream<ErrorStack> appErrors})
: _loginProviders = authModule.loginProviders,
_currentUserProfile = AuthUserProfile(
_currentFbUser,
currentProfile,
AuthEventSource.initial,
) {
/// This block receives all events from the auth state change clearing house,
/// loads the user profile if necessary, and pipes the results to the [onUserChange]
/// stream
authStateChange.asyncMap<AuthUserProfile>((authEvent) async {
final fbUser = authEvent.fbUser;
log.warning(
"User changed: ${fbUser?.displayName ?? fbUser?.email ?? 'None'}");
if (fbUser == null) {
_currentUserProfile = AuthUserProfile.empty(authEvent.source);
return _currentUserProfile!;
} else {
// Fetch the profile first thing.
try {
final profile = await authModule.loadProfile(fbUser);
final aup = AuthUserProfile(fbUser, profile, authEvent.source);
_currentUserProfile = aup;
log.warning("User loaded from server: ${profile.name}");
log.info("Profile ${profile.name} loaded");
final token = await fbUser.getIdToken();
final meta = fbUser.metadata;
log.info("Last sign in: ${meta.lastSignInTime}");
log.info("Token provider: ${fbUser.providerData}");
log.info("Updated auth token: $token");
return aup;
} on ApiResponseException catch (e) {
if (e.statusCode == kPreconditionFailed ||
e.statusCode == kPreconditionRequired) {
log.info(
"Authenticated, but no account exists yet. When the account is finished "
"being created, you will have to manually push that userProfile through");
return AuthUserProfile(fbUser, null, authEvent.source,
status: AuthStatus.partial);
} else if (e.statusCode == 401) {
log.warning(
"Got unauthorized getting profile. ${e.message} ? '(No message)' Logging you out!");
}
return AuthUserProfile.empty(authEvent.source);
} catch (e, stack) {
log.severe("Problems logging in: $e", e, stack);
return AuthUserProfile.empty(AuthEventSource.failed);
}
}
}).listen((mapped) {
_currentUserProfile = mapped;
userStateChangedStream.current = mapped;
}, cancelOnError: false).watch(this);
/// Reads from firebase auth change events, and pushes to clearing house
fb.FirebaseAuth.instance.idTokenChanges().listen((event) async {
log.info("Firebase sent auth state change: $event");
if (_currentFbUser?.uid != event?.uid) {
_currentFbUser = event;
FirebaseApiAuth.user = event;
_authStateClearinghouse
.add(AuthEvent(event, source: AuthEventSource.framework));
} else {
log.info("Ignoring duplicate state change for ${event?.uid}");
}
}).watch(this);
/// Listen for authentication failures and remove logged in users
appErrors
.where((_) {
return _.exception is ApiResponseException;
})
.where((_) => (_.exception as ApiResponseException).statusCode == 401)
.listen((_) {
log.warning("Got unauthenticated error from API.");
_authStateClearinghouse.add(AuthEvent.error(_));
_unauthenticatedErrors.add(true);
})
.watch(this);
Future.microtask(() {
initializeState(fbUser: _currentFbUser, profile: _currentUserProfile);
});
}