diff --git a/libraries/Microsoft.Bot.Builder/TokenResolver.cs b/libraries/Microsoft.Bot.Builder/TokenResolver.cs index 9f62c9fbfb..daa16e0ffb 100644 --- a/libraries/Microsoft.Bot.Builder/TokenResolver.cs +++ b/libraries/Microsoft.Bot.Builder/TokenResolver.cs @@ -20,6 +20,19 @@ internal static class TokenResolver { private static readonly TimeSpan PollingInterval = TimeSpan.FromSeconds(1); // Poll for token every 1 second. + /// + /// Inspects outgoing Activities for OAuthCards. + /// + /// The BotFrameworkAdapter used for polling the token service. + /// The ILogger implementation this TokenResolver should use. + /// The context object for the turn. + /// The activity to send. + /// Cancellation token. + /// If an is found in an outgoing activity, the polls the Bot Framework Token Service in the background. + /// When the user completes the login flow, the TokenResolver will retrieve the user's token from the service and create a TokenResponse activity to "send" to the bot, mimicking non-streaming OAuth flows. + /// + /// All bots using OAuth should query the service to ensure the user is successfully logged in before utilizing a user's token. The bot should never store the user's token. + /// public static void CheckForOAuthCards(BotFrameworkAdapter adapter, ILogger logger, ITurnContext turnContext, Activity activity, CancellationToken cancellationToken) { if (activity?.Attachments == null) @@ -37,15 +50,16 @@ public static void CheckForOAuthCards(BotFrameworkAdapter adapter, ILogger logge throw new InvalidOperationException("The OAuthPrompt's ConnectionName property is missing a value."); } - // Poll as a background task and add to the list (we don't call await here, we await all the calls together later). pollTokenTasks.Add(PollForTokenAsync(adapter, logger, turnContext, oauthCard.ConnectionName, cancellationToken)); } } if (pollTokenTasks.Any()) { - // Wait for all the poll operations to complete. - Task.WaitAll(pollTokenTasks.ToArray()); + // Run the poll operations in the background. + // On retrieving a token from the token service the TokenResolver creates an Activity to route the token to the bot to continue the conversation. + // If these Tasks are awaited and the user doesn't complete the login flow, the bot may timeout in sending its response to the channel which can cause the streaming connection to disconnect. + Task.WhenAll(pollTokenTasks.ToArray()); } } @@ -114,7 +128,7 @@ private static async Task PollForTokenAsync(BotFrameworkAdapter adapter, ILogger stopwatch.Stop(); } -#pragma warning disable CA1031 // Do not catch general exception types (for new we just log the exception and continue) +#pragma warning disable CA1031 // Do not catch general exception types (for now we just log the exception and continue) catch (Exception ex) #pragma warning restore CA1031 // Do not catch general exception types {