// Performs an MFA login interactively using Console
        public static RestClient Authenticate(string podEndpoint)
        {
            RestClient client = new RestClient(podEndpoint);

            Console.Write("Username: "******"User"] = Console.ReadLine();
            args["Version"] = "1.0";
            Dictionary<string, dynamic> startResult = client.CallApi("/security/startauthentication", args);

            // First thing to check for is whether we should repeat the call against a more specific pod name (tenant specific url):
            if(startResult["success"] && startResult["Result"].ContainsKey("PodFqdn"))
            {
                Console.WriteLine("Auth redirected to {0}", startResult["Result"]["PodFqdn"]);
                client.Endpoint = string.Format("https://{0}", startResult["Result"]["PodFqdn"]);
                startResult = client.CallApi("/security/startauthentication", args);
            }

            // Get the session id to use in handshaking for MFA
            string authSessionId = startResult["Result"]["SessionId"];
            string tenantId = startResult["Result"]["TenantId"];

            // Also get the collection of challenges we need to satisfy
            var challengeCollection = startResult["Result"]["Challenges"];

            // We need to satisfy one of each challenge collection:
            for(int x = 0; x < challengeCollection.Count; x++)
            {
                // Present the option(s) to the user
                for(int mechIdx = 0; mechIdx < challengeCollection[x]["Mechanisms"].Count; mechIdx++)
                {
                    Console.WriteLine("Option {0}: {1}", mechIdx, MechToDescription(challengeCollection[x]["Mechanisms"][mechIdx]));
                }

                int optionSelect = -1;

                if (challengeCollection[x]["Mechanisms"].Count == 1)
                {
                    optionSelect = 0;
                }
                else
                {
                    while (optionSelect < 0 || optionSelect > challengeCollection[x]["Mechanisms"].Count)
                    {
                        Console.Write("Select option and press enter: ");
                        string optEntered = Console.ReadLine();
                        int.TryParse(optEntered, out optionSelect);
                    }
                }

                AdvanceForMech(client, tenantId, authSessionId, challengeCollection[x]["Mechanisms"][optionSelect]);
            }

            return client;
        }
        private static void AdvanceForMech(RestClient client, string tenantId, string sessionId, dynamic mech)
        {
            Dictionary<string, dynamic> advanceArgs = new Dictionary<string, dynamic>();
            advanceArgs["TenantId"] = tenantId;
            advanceArgs["SessionId"] = sessionId;
            advanceArgs["MechanismId"] = mech["MechanismId"];
            advanceArgs["PersistentLogin"] = false;

            // Write prompt
            Console.Write(MechToPrompt(mech));

            // Read or poll for response.  For StartTextOob we simplify and require user to enter the response, rather
            //  than simultaenously prompting and polling, though this can be done as well.
            string answerType = mech["AnswerType"];
            switch (answerType)
            {
                case "Text":
                case "StartTextOob":
                    {
                        if (answerType == "StartTextOob")
                        {
                            // First we start oob, to get the mech activated
                            advanceArgs["Action"] = "StartOOB";
                            client.CallApi("/security/advanceauthentication", advanceArgs);
                        }

                        // Now prompt for the value to submit and do so
                        string promptResponse = ReadMaskedPassword();
                        advanceArgs["Answer"] = promptResponse;
                        advanceArgs["Action"] = "Answer";
                        var result = client.CallApi("/security/advanceauthentication", advanceArgs);
                        if (!result["success"] ||
                            !(result["Result"]["Summary"] == "StartNextChallenge" ||
                              result["Result"]["Summary"] == "LoginSuccess"))
                        {
                            throw new ApplicationException(result["Message"]);
                        }
                    }
                    break;
                case "StartOob":
                    // Pure out of band mech, simply poll until complete or fail
                    advanceArgs["Action"] = "StartOOB";
                    client.CallApi("/security/advanceauthentication", advanceArgs);

                    // Poll
                    advanceArgs["Action"] = "Poll";
                    Dictionary<string, dynamic> pollResult = new Dictionary<string, dynamic>();
                    do
                    {
                        Console.Write(".");
                        pollResult = client.CallApi("/security/advanceauthentication", advanceArgs);
                        System.Threading.Thread.Sleep(1000);
                    } while (pollResult["success"] && pollResult["Result"]["Summary"] == "OobPending");

                    // We are done polling, did it work?
                    if (!pollResult["success"] ||
                        !(pollResult["Result"]["Summary"] == "StartNextChallenge" ||
                          pollResult["Result"]["Summary"] == "LoginSuccess"))
                    {
                        throw new ApplicationException(pollResult["Message"]);
                    }
                    break;
            }
        }