/// <summary>
        /// Validate user name and phone number before sending security code
        /// </summary>
        /// <param name="userName"></param>
        /// <param name="phoneNumber"></param>
        /// <returns></returns>
        public async Task <ForgotPasswordModel> ValidateUserInfoAsync(string userName, string phoneNumber)
        {
            var model = new ForgotPasswordModel {
                ForgotPasswordStep = ForgotPasswordStep.VerifyUser
            };

            if (string.IsNullOrWhiteSpace(userName) || string.IsNullOrWhiteSpace(phoneNumber))
            {
                throw new PasswordRecoverException(model.ForgotPasswordStep, "User name and phone number are required fields.");
            }

            // 1. get records from audit to check if password attapmt within the last 20 minutes is more than 5 times
            var attempts = await _auditService.GetAuditActivityWithinTimeAsync(userName, "/passwordRecovery", 20);

            // 3. insert audit log
            await WriteAuditLog(userName);

            // 2. there are 5 or more attempts so we won't send verification code
            if (attempts.Count >= 5)
            {
                throw new PasswordRecoverException(model.ForgotPasswordStep, "Too many attempt to recover password. Please wait for 20 minutes.");
            }

            // 4. validate phone number input
            var formatedPhoneNumber = string.Empty;

            if (_phoneService.IsValidPhoneNumber(phoneNumber, out formatedPhoneNumber))
            {
                // validate user and phone number and send verification code
                var user = await _userService.GetUserByNameAsync(userName);

                var userPhoneNumber = user.Phones.FirstOrDefault(c => c.PhoneNumber == formatedPhoneNumber);
                if (userPhoneNumber != null)
                {
                    // generate password recovery token
                    var passwordRecoverToken = await _userService.GeneratePasswordResetTokenAsync(user.Id);

                    user.PasswordRecoveryToken = passwordRecoverToken;
                    await _userService.UpdateUserAsync(user.Id, user);

                    // generate security code
                    var securityCode = _phoneService.GenerateSecurityCode();

                    // save to our database
                    await _phoneService.InsertSecurityCodeAsync(userPhoneNumber.Id, securityCode);

                    // send text to user using amazon SNS
                    await _phoneService.SendSecurityCodeAsync(formatedPhoneNumber, securityCode);

                    // set user id and password recover token in model for session use
                    model.UserId = user.Id;
                }
            }

            // 5. set next step
            model.ForgotPasswordStep = ForgotPasswordStep.VerifySecurityCode;

            return(model);
        }