/// <summary>
        /// Initializes a new instance of the <see cref="OAuthPrompt"/> class.
        /// </summary>
        /// <param name="dialogId">The ID to assign to this prompt.</param>
        /// <param name="settings">Additional OAuth settings to use with this instance of the prompt.</param>
        /// <param name="validator">Optional, a <see cref="PromptValidator{FoundChoice}"/> that contains additional,
        /// custom validation for this prompt.</param>
        /// <remarks>The value of <paramref name="dialogId"/> must be unique within the
        /// <see cref="DialogSet"/> or <see cref="ComponentDialog"/> to which the prompt is added.</remarks>
        public OAuthPrompt(string dialogId, OAuthPromptSettings settings, PromptValidator <TokenResponse> validator = null)
            : base(dialogId)
        {
            if (string.IsNullOrWhiteSpace(dialogId))
            {
                throw new ArgumentNullException(nameof(dialogId));
            }

            _settings  = settings ?? throw new ArgumentNullException(nameof(settings));
            _validator = validator;
        }
        public static async Task SignOutUserAsync(ITurnContext turnContext, OAuthPromptSettings settings, CancellationToken cancellationToken)
        {
            var userTokenClient = turnContext.TurnState.Get <UserTokenClient>();

            if (userTokenClient != null)
            {
                await userTokenClient.SignOutUserAsync(turnContext.Activity.From.Id, settings.ConnectionName, turnContext.Activity.ChannelId, cancellationToken).ConfigureAwait(false);
            }
            else if (turnContext.Adapter is IExtendedUserTokenProvider adapter)
            {
                await adapter.SignOutUserAsync(turnContext, settings.OAuthAppCredentials, settings.ConnectionName, turnContext.Activity?.From?.Id, cancellationToken).ConfigureAwait(false);
            }
            else
            {
                throw new NotSupportedException("OAuth prompt is not supported by the current adapter");
            }
        }
        /// <summary>
        /// Shared implementation of the SendOAuthCardAsync function. This is intended for internal use, to
        /// consolidate the implementation of the OAuthPrompt and OAuthInput. Application logic should use
        /// those dialog classes.
        /// </summary>
        /// <param name="settings">OAuthSettings.</param>
        /// <param name="turnContext">ITurnContext.</param>
        /// <param name="prompt">IMessageActivity.</param>
        /// <param name="cancellationToken">CancellationToken.</param>
        /// <returns>A <see cref="Task"/> representing the result of the asynchronous operation.</returns>
        public static async Task SendOAuthCardAsync(OAuthPromptSettings settings, ITurnContext turnContext, IMessageActivity prompt, CancellationToken cancellationToken)
        {
            BotAssert.ContextNotNull(turnContext);

            // Ensure prompt initialized
            prompt ??= Activity.CreateMessageActivity();

            if (prompt.Attachments == null)
            {
                prompt.Attachments = new List <Attachment>();
            }

            // Append appropriate card if missing
            if (!ChannelSupportsOAuthCard(turnContext.Activity.ChannelId))
            {
                if (!prompt.Attachments.Any(a => a.Content is SigninCard))
                {
                    var signInResource = await UserTokenAccess.GetSignInResourceAsync(turnContext, settings, cancellationToken).ConfigureAwait(false);

                    prompt.Attachments.Add(new Attachment
                    {
                        ContentType = SigninCard.ContentType,
                        Content     = new SigninCard
                        {
                            Text    = settings.Text,
                            Buttons = new[]
                            {
                                new CardAction
                                {
                                    Title = settings.Title,
                                    Value = signInResource.SignInLink,
                                    Type  = ActionTypes.Signin,
                                },
                            },
                        },
                    });
                }
            }
            else if (!prompt.Attachments.Any(a => a.Content is OAuthCard))
            {
                var cardActionType = ActionTypes.Signin;
                var signInResource = await UserTokenAccess.GetSignInResourceAsync(turnContext, settings, cancellationToken).ConfigureAwait(false);

                var value = signInResource.SignInLink;

                // use the SignInLink when
                //   in speech channel or
                //   bot is a skill or
                //   an extra OAuthAppCredentials is being passed in
                if (turnContext.Activity.IsFromStreamingConnection() ||
                    (turnContext.TurnState.Get <ClaimsIdentity>(BotAdapter.BotIdentityKey) is ClaimsIdentity botIdentity && SkillValidation.IsSkillClaim(botIdentity.Claims)) ||
                    settings.OAuthAppCredentials != null)
                {
                    if (turnContext.Activity.ChannelId == Channels.Emulator)
                    {
                        cardActionType = ActionTypes.OpenUrl;
                    }
                }
                else if ((settings.ShowSignInLink != null && settings.ShowSignInLink == false) ||
                         (settings.ShowSignInLink == null && !ChannelRequiresSignInLink(turnContext.Activity.ChannelId)))
                {
                    value = null;
                }

                prompt.Attachments.Add(new Attachment
                {
                    ContentType = OAuthCard.ContentType,
                    Content     = new OAuthCard
                    {
                        Text           = settings.Text,
                        ConnectionName = settings.ConnectionName,
                        Buttons        = new[]
                        {
                            new CardAction
                            {
                                Title = settings.Title,
                                Text  = settings.Text,
                                Type  = cardActionType,
                                Value = value
                            },
                        },
                        TokenExchangeResource = signInResource.TokenExchangeResource,
                    },
                });
            }
 public OAuthPromptInternal(OAuthPromptSettings settings, PromptValidator <TokenResult> validator = null)
 {
     _settings        = settings ?? throw new ArgumentException(nameof(settings));
     _promptValidator = validator;
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="CloudOAuthPrompt"/> class.
 /// </summary>
 /// <param name="settings">Additional OAuth settings to use with this instance of the prompt.</param>
 /// <param name="validator">A custom validator that can be used against Message activities.</param>
 public CloudOAuthPrompt(OAuthPromptSettings settings, PromptValidator <TokenResponse> validator = null)
 {
     _settings  = settings ?? throw new ArgumentNullException(nameof(settings));
     _validator = validator;
 }
        public static async Task <TokenResponse> ExchangeTokenAsync(ITurnContext turnContext, OAuthPromptSettings settings, TokenExchangeRequest tokenExchangeRequest, CancellationToken cancellationToken)
        {
            var userTokenClient = turnContext.TurnState.Get <UserTokenClient>();

            if (userTokenClient != null)
            {
                var userId    = turnContext.Activity.From.Id;
                var channelId = turnContext.Activity.ChannelId;
                return(await userTokenClient.ExchangeTokenAsync(userId, settings.ConnectionName, channelId, tokenExchangeRequest, cancellationToken).ConfigureAwait(false));
            }
            else if (turnContext.Adapter is IExtendedUserTokenProvider adapter)
            {
                return(await adapter.ExchangeTokenAsync(turnContext, settings.ConnectionName, turnContext.Activity.From.Id, tokenExchangeRequest, cancellationToken).ConfigureAwait(false));
            }
            else
            {
                throw new NotSupportedException("OAuth prompt is not supported by the current adapter");
            }
        }
        /// <summary>
        /// Helper function used in BeginDialog.
        /// </summary>
        /// <param name="userTokenClient">The userTokenClient.</param>
        /// <param name="settings">The oauth settings.</param>
        /// <param name="turnContext">The turncontext.</param>
        /// <param name="prompt">A message activity for the prompt.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>A Task.</returns>
        public static async Task SendOAuthCardAsync(UserTokenClient userTokenClient, OAuthPromptSettings settings, ITurnContext turnContext, IMessageActivity prompt, CancellationToken cancellationToken)
        {
            // Ensure prompt initialized
            prompt ??= Activity.CreateMessageActivity();

            if (prompt.Attachments == null)
            {
                prompt.Attachments = new List <Attachment>();
            }

            // Append appropriate card if missing
            if (!ChannelSupportsOAuthCard(turnContext.Activity.ChannelId))
            {
                if (!prompt.Attachments.Any(a => a.Content is SigninCard))
                {
                    var signInResource = await userTokenClient.GetSignInResourceAsync(settings.ConnectionName, turnContext.Activity, null, cancellationToken).ConfigureAwait(false);

                    prompt.Attachments.Add(new Attachment
                    {
                        ContentType = SigninCard.ContentType,
                        Content     = new SigninCard
                        {
                            Text    = settings.Text,
                            Buttons = new[]
                            {
                                new CardAction
                                {
                                    Title = settings.Title,
                                    Value = signInResource.SignInLink,
                                    Type  = ActionTypes.Signin,
                                },
                            },
                        },
                    });
                }
            }
            else if (!prompt.Attachments.Any(a => a.Content is OAuthCard))
            {
                var cardActionType = ActionTypes.Signin;
                var signInResource = await userTokenClient.GetSignInResourceAsync(settings.ConnectionName, turnContext.Activity, null, cancellationToken).ConfigureAwait(false);

                var value = signInResource.SignInLink;

                // use the SignInLink when
                //   in speech channel or
                //   bot is a skill or
                // TODO: the OauthPrompt code also checked for || settings.OAuthAppCredentials != null
                if (turnContext.Activity.IsFromStreamingConnection() ||
                    IsSkill(turnContext.TurnState.Get <ClaimsIdentity>(BotAdapter.BotIdentityKey)))
                {
                    if (turnContext.Activity.ChannelId == Channels.Emulator)
                    {
                        cardActionType = ActionTypes.OpenUrl;
                    }
                }
                else if (!ChannelRequiresSignInLink(turnContext.Activity.ChannelId))
                {
                    value = null;
                }

                prompt.Attachments.Add(new Attachment
                {
                    ContentType = OAuthCard.ContentType,
                    Content     = new OAuthCard
                    {
                        Text           = settings.Text,
                        ConnectionName = settings.ConnectionName,
                        Buttons        = new[]
                        {
                            new CardAction
                            {
                                Title = settings.Title,
                                Text  = settings.Text,
                                Type  = cardActionType,
                                Value = value
                            },
                        },
                        TokenExchangeResource = signInResource.TokenExchangeResource,
                    },
                });
            }

            // Add the login timeout specified in OAuthPromptSettings to TurnState so it can be referenced if polling is needed
            if (!turnContext.TurnState.ContainsKey(TurnStateConstants.OAuthLoginTimeoutKey) && settings.Timeout.HasValue)
            {
                turnContext.TurnState.Add <object>(TurnStateConstants.OAuthLoginTimeoutKey, TimeSpan.FromMilliseconds(settings.Timeout.Value));
            }

            // Set input hint
            if (string.IsNullOrEmpty(prompt.InputHint))
            {
                prompt.InputHint = InputHints.AcceptingInput;
            }

            await turnContext.SendActivityAsync(prompt, cancellationToken).ConfigureAwait(false);
        }