public async Task <bool> Login(string userName, ISecretProvider secretProvider, ISecretPersistor secretPersistor = null) { if (string.IsNullOrWhiteSpace(userName)) { throw new ArgumentException($"{nameof(userName)} not specified.", nameof(userName)); } if (secretProvider == null) { throw new ArgumentNullException(nameof(secretProvider)); } if (IsLoggedIn) { throw new InvalidOperationException("The client is already logged in."); } if (secretProvider.TryGetUserPasswordHash(out string userPasswordHash) == false) { string userPassword = await secretProvider.GetPassword(); FormUrlEncodedContent formContent = CreateFormContent(new[] { new KeyValuePair <string, string>("username_or_email", userName) }); SaltResult saltResult = await _httpClient.PostFormData <SaltResult>(API_SALT_URI, formContent); if (CheckResultStatus(saltResult)) { userPasswordHash = BCrypt.HashPassword(userPassword, saltResult.Salt); } else { return(false); } } LoginInfo loginInfo = new LoginInfo(userName, userPasswordHash, secretProvider, secretPersistor); if (await TryLogin(loginInfo)) { _loginInfo = loginInfo; _privateRootFolder = WsFolder.CreateRootFolder(this, true); _publicRootFolder = WsFolder.CreateRootFolder(this, false); secretPersistor?.SaveUserPasswordHash(userPasswordHash); return(true); } return(false); }