private async Task <Uri> SeleniumAcquireAuthAsync(
            Uri authorizationUri,
            Uri redirectUri,
            CancellationToken cancellationToken)
        {
            NullLogger nullLogger = new NullLogger();

            using (var driver = InitDriverAndGoToUrl(authorizationUri.OriginalString))
            {
                var listener              = new TcpInterceptor(nullLogger);
                Uri authCodeUri           = null;
                var listenForAuthCodeTask = listener.ListenToSingleRequestAndRespondAsync(
                    redirectUri.Port,
                    (uri) =>
                {
                    Trace.WriteLine("Intercepted an auth code url: " + uri.ToString());
                    authCodeUri = uri;

                    return(GetMessageToShowInBroswerAfterAuth(uri));
                },
                    cancellationToken);

                // Run the TCP listener and the selenium automation in parallel
                var seleniumAutomationTask = Task.Factory.StartNew(() => _seleniumAutomationLogic(driver));

                await Task.WhenAny(seleniumAutomationTask, listenForAuthCodeTask)
                .ConfigureAwait(false);

                if (listenForAuthCodeTask.Status == TaskStatus.RanToCompletion)
                {
                    return(authCodeUri);
                }

                if (seleniumAutomationTask.IsFaulted)
                {
                    Trace.WriteLine("The selenium automation failed: " + seleniumAutomationTask.Exception.Message);
                    RecordException(driver, seleniumAutomationTask.Exception);
                    throw seleniumAutomationTask.Exception;
                }

                if (listenForAuthCodeTask.IsCanceled)
                {
                    Trace.WriteLine("The TCP listener has timed out (or was canceled).");
                    if (!cancellationToken.IsCancellationRequested)
                    {
                        Assert.Fail("The TCP listener is in a canceled state, but cancellation has not been requested!");
                    }

                    throw new OperationCanceledException(cancellationToken);
                }

                if (listenForAuthCodeTask.IsFaulted)
                {
                    Trace.WriteLine("The TCP listener failed.");
                    RecordException(driver, listenForAuthCodeTask.Exception);
                    throw listenForAuthCodeTask.Exception;
                }

                throw new InvalidOperationException(
                          $"Unknown exception: selenium status: {seleniumAutomationTask.Status} TCP listener status: {listenForAuthCodeTask.Status}");
            }
        }
        private async Task <Uri> SeleniumAcquireAuthAsync(
            Uri authorizationUri,
            Uri redirectUri,
            CancellationToken externalCancellationToken)
        {
            using (var driver = InitDriverAndGoToUrl(authorizationUri.OriginalString))
            {
                var listener    = new TcpInterceptor(_logger);
                Uri authCodeUri = null;

                // Run the TCP listener and the selenium automation in parallel
                // but make sure to start the TCP listener first
                CancellationTokenSource innerSource = new CancellationTokenSource();
                var tcpCancellationToken            = CancellationTokenSource.CreateLinkedTokenSource(
                    innerSource.Token,
                    externalCancellationToken);

                Task <Uri> listenForAuthCodeTask = listener.ListenToSingleRequestAndRespondAsync(
                    redirectUri.Port,
                    (uri) =>
                {
                    authCodeUri = uri;

                    _logger.Info("Auth code intercepted. Writing message back to browser");
                    return(GetMessageToShowInBroswerAfterAuth(uri));
                },
                    tcpCancellationToken.Token);

                var seleniumAutomationTask = Task.Factory.StartNew(() =>
                {
                    _seleniumAutomationLogic(driver);
                    _logger.Info("Selenium automation finished");
                });

                // There is no guarantee over which task will finish first - TCP listener or Selenium automation
                // as the TCP listener has some post processing to do (extracting the url etc.)
                await Task.WhenAny(seleniumAutomationTask, listenForAuthCodeTask)
                .ConfigureAwait(false);

                // No need to wait to post a nice message in the browser
                if (authCodeUri != null)
                {
                    return(authCodeUri);
                }

                if (seleniumAutomationTask.IsFaulted)
                {
                    Trace.WriteLine("The selenium automation failed: " + seleniumAutomationTask.Exception.Message);
                    RecordException(driver, seleniumAutomationTask.Exception);
                    throw seleniumAutomationTask.Exception;
                }

                if (listenForAuthCodeTask.IsCanceled)
                {
                    Trace.WriteLine("The TCP listener has timed out (or was canceled).");
                    if (!externalCancellationToken.IsCancellationRequested)
                    {
                        Assert.Fail("The TCP listener is in a canceled state, but cancellation has not been requested!");
                    }

                    throw new OperationCanceledException(externalCancellationToken);
                }

                if (listenForAuthCodeTask.IsFaulted)
                {
                    Trace.WriteLine("The TCP listener failed.");
                    RecordException(driver, listenForAuthCodeTask.Exception);
                    throw listenForAuthCodeTask.Exception;
                }

                _logger.Info($"Selenium finished, but TCP listener is still going. " +
                             $"Selenium status: {seleniumAutomationTask.Status} " +
                             $"TCP listener status: { listenForAuthCodeTask.Status}. ");

                // At this point we need to give the TcpListener some time to complete
                // but not too much as it should be fast
                await Task.WhenAny(Task.Delay(tcpTimeoutAfterSelenium), listenForAuthCodeTask).ConfigureAwait(false);

                if (authCodeUri != null)
                {
                    return(authCodeUri);
                }

                innerSource.Cancel();
                throw new InvalidOperationException(
                          $"Unknown exception: selenium status: {seleniumAutomationTask.Status} TCP listener status: {listenForAuthCodeTask.Status}. " +
                          $"Possible cause - the redirect Uri used is not the one configured." +
                          $" A screen shot will be stored in the test results for you to inspect.");
            }
        }