Implementation
@override
Future<AuthUser<User>> signInWithEmailAndPassword(
{required String email,
required String password,
String? merchantId}) async {
final MonitoringService monitoringService = core.get<MonitoringService>();
var trace =
await monitoringService.createTrace(name: 'signInWithEmailAndPassword');
trace.start();
try {
if (!isReady) {
throw LittlefishFirebaseAuthException('AUTH_INIT_000',
'$providerName: Firebase is not initialized, $providerName cannot sign in with email and password');
}
if (email.isEmpty || password.isEmpty) {
throw LittlefishFirebaseAuthException('AUTH_007',
'$providerName: Email or password is empty, $providerName cannot sign in with email and password');
}
AuthUser<User>? authUser;
switch (authMode) {
case AuthMode.providerOnly:
logger.debug(
this,
"$providerName: Signing in with email:$email and password with conditions",
);
// PART 1: Sign in with provider
var r = await kInstance?.signInWithEmailAndPassword(
email: email,
password: password,
);
if (r?.user == null) {
throw LittlefishFirebaseAuthException('AUTH_008',
'$providerName: Sign in with email and password failed, $providerName cannot locate user information post-logon');
}
kUserCredential = r!.credential;
authUser = FirebaseAuthUser(
kUser: r.user!,
additionalUserInfo:
_convertAdditionalUserInfo(r.additionalUserInfo),
baseUserId: r.user?.uid ?? '',
baseUserFirstName: r.user?.displayName ?? '',
baseUserLastName: r.user?.displayName ?? '',
baseUserEmail: r.user?.email ?? '',
baseUserRegisteredDate:
r.user?.metadata.creationTime ?? DateTime.now(),
baseUserMobileNumber: r.user?.phoneNumber ?? '',
baseUserProfileImageUri: r.user?.photoURL ?? '',
baseUserGender: UserGender.notSpecified,
baseUserDisplayName: r.user?.displayName ?? '',
baseUserEmailVerified: r.user?.emailVerified ?? false,
);
logger.info(
this,
"$providerName: Signed in with email:$email and password",
);
// PART 2: Call custom auth to get token
final idToken = await r.user?.getIdToken();
authenticationResult = AuthResult(
token: idToken,
accessToken: idToken,
authenticated: !(r.user?.isAnonymous ?? true),
businesses: [],
message: 'Signed in with provider only',
otpId: '',
refreshToken: '',
sessionId: '',
verified: r.user?.emailVerified ?? false,
);
// Fire-and-forget: track login for providerOnly since no backend
// login endpoint is called (TryWriteLoginTracking never fires).
_trackLoginEvent(authUser);
break;
case AuthMode.customOnly:
await signInApi(email, password);
if (authenticationResult?.accessToken == null) {
throw LittlefishFirebaseAuthException('AUTH_009',
'$providerName: Custom authentication failed, no token received');
}
authUser = await signInWithCustomToken(
token: authenticationResult!.accessToken!);
break;
case AuthMode.providerAndCustom:
logger.debug(
this,
"$providerName: Signing in with email:$email and password",
);
// PART 1: Sign in with provider
var r = await kInstance?.signInWithEmailAndPassword(
email: email,
password: password,
);
// authenticationResult = AuthResult();
if (r?.user == null) {
throw LittlefishFirebaseAuthException('AUTH_008',
'$providerName: Sign in with email and password failed, $providerName cannot locate user information post-logon');
}
kUserCredential = r!.credential;
authUser = FirebaseAuthUser(
kUser: r.user!,
additionalUserInfo:
_convertAdditionalUserInfo(r.additionalUserInfo),
baseUserId: r.user?.uid ?? '',
baseUserFirstName: r.user?.displayName ?? '',
baseUserLastName: r.user?.displayName ?? '',
baseUserEmail: r.user?.email ?? '',
baseUserRegisteredDate:
r.user?.metadata.creationTime ?? DateTime.now(),
baseUserMobileNumber: r.user?.phoneNumber ?? '',
baseUserProfileImageUri: r.user?.photoURL ?? '',
baseUserGender: UserGender.notSpecified,
baseUserDisplayName: r.user?.displayName ?? '',
baseUserEmailVerified: r.user?.emailVerified ?? false,
);
logger.info(
this,
"$providerName: Signed in with email:$email and password",
);
// PART 2: Call custom auth to get token
final idToken = await r.user?.getIdToken();
authenticationResult = AuthResult(
token: idToken,
accessToken: idToken,
authenticated: !(r.user?.isAnonymous ?? true),
businesses: [],
message: 'Signed in with provider only',
otpId: '',
refreshToken: '',
sessionId: '',
verified: r.user?.emailVerified ?? false,
);
try {
authenticationResult = await signInApi(email, password);
await signInWithCustomToken(token: authenticationResult!.token!);
} catch (e, st) {
logger.error('FirebaseAuthService',
'Custom authentication failed, signing out from Firebase to ensure clean state. Error: $e',
error: e, stackTrace: st);
await signOut();
throw LittlefishFirebaseAuthException(
AuthenticationErrorCodes.customAuthFailedSigningOut.code,
AuthenticationErrorCodes.customAuthFailedSigningOut.message,
cause: e,
);
}
break;
case AuthMode.providerAndCustomConditions:
logger.debug(
this,
"$providerName: Signing in with email:$email and password with conditions",
);
// PART 1: Sign in with provider
var r = await kInstance?.signInWithEmailAndPassword(
email: email,
password: password,
);
if (r?.user == null) {
throw LittlefishFirebaseAuthException('AUTH_008',
'$providerName: Sign in with email and password failed, $providerName cannot locate user information post-logon');
}
kUserCredential = r!.credential;
authUser = FirebaseAuthUser(
kUser: r.user!,
additionalUserInfo:
_convertAdditionalUserInfo(r.additionalUserInfo),
baseUserId: r.user?.uid ?? '',
baseUserFirstName: r.user?.displayName ?? '',
baseUserLastName: r.user?.displayName ?? '',
baseUserEmail: r.user?.email ?? '',
baseUserRegisteredDate:
r.user?.metadata.creationTime ?? DateTime.now(),
baseUserMobileNumber: r.user?.phoneNumber ?? '',
baseUserProfileImageUri: r.user?.photoURL ?? '',
baseUserGender: UserGender.notSpecified,
baseUserDisplayName: r.user?.displayName ?? '',
baseUserEmailVerified: r.user?.emailVerified ?? false,
);
logger.info(
this,
"$providerName: Signed in with email:$email and password",
);
// PART 2: Call custom auth to get token
try {
authenticationResult = await signInApiWithConditions(
email, password, merchantId ?? '', settings.platformType);
await signInWithCustomToken(token: authenticationResult!.token!);
} catch (e, st) {
logger.error('FirebaseAuthService',
'Custom authentication failed, signing out from Firebase to ensure clean state. Error: $e',
error: e, stackTrace: st);
await signOut();
throw LittlefishFirebaseAuthException(
AuthenticationErrorCodes.customAuthFailedSigningOut.code,
AuthenticationErrorCodes.customAuthFailedSigningOut.message,
cause: e,
);
}
break;
}
return authUser;
} on FirebaseAuthException catch (e) {
throw _handleFirebaseAuthException(e);
} catch (e) {
if (e is LittlefishException) {
rethrow;
}
throw LittlefishFirebaseAuthException(
'AUTH_014',
'An unexpected error occurred during sign in with email and password.',
cause: e,
);
} finally {
trace.stop();
}
}