signIn method

Future<AuthResult> signIn(
  1. AuthProvider provider
)

소셜 로그인 실행

provider에 따라 해당 소셜 로그인을 실행합니다.

반환값

AuthResult를 반환합니다:

  • 성공 시: result.success == true, result.user 사용 가능
  • 실패 시: result.success == false, result.errorMessage 확인

사용 예시

기본 사용법 (if-else)

final result = await kAuth.signIn(AuthProvider.kakao);

if (result.success) {
  print('환영합니다, ${result.user?.displayName}!');
  navigateToHome();
} else {
  print('로그인 실패: ${result.errorMessage}');
  showErrorDialog(result.errorMessage);
}

함수형 스타일 (fold)

final result = await kAuth.signIn(AuthProvider.kakao);

result.fold(
  onSuccess: (user) {
    print('환영합니다, ${user.displayName}!');
    navigateToHome(user);
  },
  onFailure: (failure) {
    print('실패: ${failure.message}');
    showErrorDialog(failure.message);
  },
);

상세 처리 (when - 성공/취소/실패 구분)

final result = await kAuth.signIn(AuthProvider.kakao);

result.when(
  success: (user) {
    print('로그인 성공: ${user.displayName}');
    navigateToHome(user);
  },
  cancelled: () {
    print('사용자가 로그인을 취소했습니다');
    showSnackBar('로그인이 취소되었습니다');
  },
  failure: (failure) {
    print('로그인 실패: ${failure.message}');
    showErrorDialog(failure.message);
  },
);

체이닝 스타일

final result = await kAuth.signIn(AuthProvider.kakao);

result
  .onSuccess((user) {
    saveUserToDatabase(user);
    navigateToHome(user);
  })
  .onFailure((failure) {
    logError(failure.code, failure.message);
    showError(failure.message);
  });

Implementation

Future<AuthResult> signIn(AuthProvider provider) async {
  _ensureInitialized();

  // 동시 로그인 방지
  if (_signInLock != null) {
    KAuthLogger.warning('로그인 진행 중 - 대기', provider: provider.name);
    return _signInLock!.future;
  }

  _signInLock = Completer<AuthResult>();

  KAuthLogger.info(
    '로그인 시작',
    provider: provider.name,
  );

  final providerImpl = _providers[provider];
  if (providerImpl == null) {
    final error = KAuthError.fromCode(
      ErrorCodes.providerNotConfigured,
      details: {'provider': provider.name},
    );
    final result = AuthResult.failure(
      provider: provider,
      errorMessage: error.message,
      errorCode: error.code,
      errorHint: error.hint,
    );
    _signInLock!.complete(result);
    _signInLock = null;
    return result;
  }

  final stopwatch = Stopwatch()..start();

  try {
    // Provider signIn 호출 (다형성 활용)
    final result = await providerImpl.signIn();

    stopwatch.stop();

    if (result.success && result.user != null) {
      _lastResult = result;
      _emitAuthState(result.user);

      // 로그인 콜백 호출
      if (onSignIn != null) {
        try {
          final tokens = AuthTokens(
            accessToken: result.accessToken,
            refreshToken: result.refreshToken,
            idToken: result.idToken,
            expiresAt: result.expiresAt,
          );

          _serverToken = await onSignIn!(provider, tokens, result.user!);

          KAuthLogger.debug(
            '로그인 콜백 완료',
            provider: provider.name,
            data: {'hasServerToken': _serverToken != null},
          );
        } catch (e) {
          KAuthLogger.error(
            '로그인 콜백 실패',
            provider: provider.name,
            error: e,
          );
        }
      }

      // 세션 저장
      await _saveSession(result);

      KAuthLogger.info(
        '로그인 성공',
        provider: provider.name,
        data: {
          'userId': result.user?.id,
          'hasEmail': result.user?.email != null,
          'duration': '${stopwatch.elapsedMilliseconds}ms',
        },
      );
    } else if (!result.success) {
      KAuthLogger.warning(
        '로그인 실패',
        provider: provider.name,
        data: {
          'errorCode': result.errorCode,
          'errorMessage': result.errorMessage,
          'duration': '${stopwatch.elapsedMilliseconds}ms',
        },
      );
    }

    // 동시 로그인 lock 해제
    _signInLock?.complete(result);
    _signInLock = null;

    return result;
  } catch (e) {
    // 예외 발생 시에도 lock 해제 보장
    final errorResult = AuthResult.failure(
      provider: provider,
      errorMessage: '로그인 중 예기치 않은 오류가 발생했습니다.',
      errorCode: ErrorCodes.loginFailed,
    );
    _signInLock?.complete(errorResult);
    _signInLock = null;
    return errorResult;
  }
}