linkEmailPassword method

  1. @override
Future<Either<AuthServiceLinkFailure, Unit>> linkEmailPassword(
  1. String email,
  2. String password
)
override

Link anonymous account to email/password credentials

Converts an anonymous user to a permanent account while preserving the UID. After linking, the user can sign in with email/password on other devices.

Returns AuthServiceLinkFailure.emailAlreadyInUse if email is already registered. Returns AuthServiceLinkFailure.weakPassword if password is less than 6 characters.

Implementation

@override
Future<Either<AuthServiceLinkFailure, Unit>> linkEmailPassword(
  String email,
  String password,
) async {
  try {
    final user = _fbAuth.currentUser;
    if (user == null) {
      logw('linkEmailPassword: No user logged in');
      return left(AuthServiceLinkFailure.userNotLoggedIn);
    }

    // Check if user already has email/password credential linked.
    // We check for email provider instead of isAnonymous because users
    // signed in with custom tokens (e.g., server-created anonymous users)
    // have isAnonymous=false but should still be able to link email/password.
    final hasEmailProvider = user.providerData.any(
      (provider) => provider.providerId == 'password',
    );
    if (hasEmailProvider) {
      logw('linkEmailPassword: User already has email/password linked');
      return left(AuthServiceLinkFailure.credentialAlreadyInUse);
    }

    logd('linkEmailPassword: Linking account to email: $email');

    // Create email/password credential
    final credential = fb_auth.EmailAuthProvider.credential(
      email: email,
      password: password,
    );

    // Link the credential to the anonymous account
    await user.linkWithCredential(credential);
    logd('linkEmailPassword: Successfully linked account');

    return right(unit);
  } on fb_auth.FirebaseAuthException catch (e) {
    loge(e, 'linkEmailPassword failed');
    switch (e.code) {
      case 'email-already-in-use':
        return left(AuthServiceLinkFailure.emailAlreadyInUse);
      case 'weak-password':
        return left(AuthServiceLinkFailure.weakPassword);
      case 'invalid-email':
        return left(AuthServiceLinkFailure.invalidEmail);
      case 'invalid-credential':
        return left(AuthServiceLinkFailure.invalidCredential);
      case 'credential-already-in-use':
        return left(AuthServiceLinkFailure.credentialAlreadyInUse);
      case 'requires-recent-login':
        return left(AuthServiceLinkFailure.requiresRecentLogin);
      default:
        return left(AuthServiceLinkFailure.unexpected);
    }
  } catch (e) {
    loge(e, 'linkEmailPassword failed');
    return left(AuthServiceLinkFailure.unexpected);
  }
}