internal static HttpCookies MarkDeviceTrusted(UserInfo userInfo,
                                                      bool trust,
                                                      string token,
                                                      string mfaToken,
                                                      RestClient rest)
        {
            var response = rest.PostJson <R.TrustMfa>(TrustUrl(userInfo),
                                                      new Dictionary <string, object>
            {
                ["trustmfa"] = new Dictionary <string, object>
                {
                    ["trust"] = trust
                },
            },
                                                      headers: new Dictionary <string, string>
            {
                ["X-ZCSRF-TOKEN"]   = $"iamcsrcoo={token}",
                ["Z-Authorization"] = $"Zoho-ticket {mfaToken}",
            },
                                                      cookies: new Dictionary <string, string>
            {
                ["iamcsr"] = token
            });

            if (!response.IsSuccessful)
            {
                throw MakeErrorOnFailedRequest(response);
            }

            var status = response.Data;

            if (status.StatusCode / 100 == 2 && SuccessErrorCodes.Contains(status.Code))
            {
                return(response.Cookies);
            }

            throw MakeInvalidResponseError(status);
        }
        internal static HttpCookies LogIn(UserInfo userInfo,
                                          string password,
                                          string token,
                                          IUi ui,
                                          ISecureStorage storage,
                                          RestClient rest)
        {
            var cookies = new Dictionary <string, string> {
                ["iamcsr"] = token
            };

            // TODO: Verify this!
            // Check if we have a "remember me" token saved from one of the previous sessions
            var(rememberMeKey, rememberMeValue) = LoadRememberMeToken(storage);
            bool haveRememberMe = !rememberMeKey.IsNullOrEmpty() && !rememberMeValue.IsNullOrEmpty();

            if (haveRememberMe)
            {
                cookies[rememberMeKey] = rememberMeValue;
            }

            var response = rest.PostJson <R.LogIn>(LogInUrl(userInfo, Os.UnixMilliseconds()),
                                                   parameters: new Dictionary <string, object>
            {
                ["passwordauth"] = new Dictionary <string, string>
                {
                    ["password"] = password
                },
            },
                                                   headers: new Dictionary <string, string>
            {
                ["X-ZCSRF-TOKEN"] = $"iamcsrcoo={token}"
            },
                                                   cookies: cookies);

            if (!response.IsSuccessful)
            {
                throw MakeErrorOnFailedRequest(response);
            }

            var status = response.Data;

            if (status.StatusCode / 100 == 2)
            {
                // Successfully logged in
                if (SuccessErrorCodes.Contains(status.Code))
                {
                    return(response.Cookies);
                }

                // MFA required
                if (status.Code == "MFA302")
                {
                    return(LogInMfa(userInfo, status.Result, token, ui, storage, rest));
                }

                throw MakeInvalidResponseError(status);
            }

            var error = GetError(status);

            switch (error.Code)
            {
            // Bad password
            case "IN102":
                throw new BadCredentialsException("The password is incorrect");

            // Captcha
            case "IN107":
            case "IN108":
                throw new UnsupportedFeatureException("Captcha is not supported");
            }

            // Some other error
            throw MakeInvalidResponseError(status);
        }