3
votes

Can't find good example of auth flow for link unfurling. I managed to run oauth flow using this example. But after user provided login and password and bot hits OnTeamsAppBasedLinkQueryAsync second time GetUserTokenAsync still returns null. So I don't follow where should I get then token from when auth flow is finished. Should I persist it somehow? Will Teams send me the token on every request or how it should work?

So in my case following code always returns null:

var tokenResponse = await (turnContext.Adapter as IUserTokenProvider)
    .GetUserTokenAsync(turnContext, _connectionName, default(string),
        cancellationToken: cancellationToken);
1
It looks like you're passing default(string) instead of the 'magic code'? A few lines above your link there's a comment that says "When the Bot Service Auth flow completes, the action.State will contain a magic code used for verification."stuartd
Yeah, but documentation for that method says that magicCode is optional: docs.microsoft.com/en-us/dotnet/api/… I believe code is for kind of sms confirmation or something like that. Anyway it's not available in unfurling flow as AppBasedLinkQuery has single Url property.Andrew
So it does. Sorry about that.stuartd
Yes, I read it several times. The problem is that I don’t have a dialog, I’m in link unfurling flow so I don’t have state and can’t send message. Do you mean something specific I should check?Andrew

1 Answers

1
votes

It seems the 'state' field is not present on AppBasedLinkQuery. When the auth flow completes, OnTeamsAppBasedLinkQueryAsync will be called again and the turnContext.Activity.Value will contain the url and the 'state' (or magic code). We will get this field added to AppBasedLinkQuery (created an issue here: microsoft/botbuilder-dotnet#3429 ).

A workaround is to retrieve the state/magiccode directly from the Activity.Value Something like:

 protected async override Task<MessagingExtensionResponse> OnTeamsAppBasedLinkQueryAsync(ITurnContext<IInvokeActivity> turnContext, AppBasedLinkQuery query, CancellationToken cancellationToken)
        {
            var magicCode = string.Empty;
            var state = (turnContext.Activity.Value as Newtonsoft.Json.Linq.JObject).Value<string>("state");
            if (!string.IsNullOrEmpty(state))
            {
                int parsed = 0;
                if (int.TryParse(state, out parsed))
                {
                    magicCode = parsed.ToString();
                }
            }

            var tokenResponse = await(turnContext.Adapter as IUserTokenProvider).GetUserTokenAsync(turnContext, _connectionName, magicCode, cancellationToken: cancellationToken);
            if (tokenResponse == null || string.IsNullOrEmpty(tokenResponse.Token))
            {
                // There is no token, so the user has not signed in yet.

                // Retrieve the OAuth Sign in Link to use in the MessagingExtensionResult Suggested Actions
                var signInLink = await(turnContext.Adapter as IUserTokenProvider).GetOauthSignInLinkAsync(turnContext, _connectionName, cancellationToken);

                return new MessagingExtensionResponse
                {
                    ComposeExtension = new MessagingExtensionResult
                    {
                        Type = "auth",
                        SuggestedActions = new MessagingExtensionSuggestedAction
                        {
                            Actions = new List<CardAction>
                                {
                                    new CardAction
                                    {
                                        Type = ActionTypes.OpenUrl,
                                        Value = signInLink,
                                        Title = "Bot Service OAuth",
                                    },
                                },
                        },
                    },
                };
            }

            var heroCard = new ThumbnailCard
            {
                Title = "Thumbnail Card",
                Text = query.Url,
                Images = new List<CardImage> { new CardImage("https://raw.githubusercontent.com/microsoft/botframework-sdk/master/icon.png") },
            };

            var attachments = new MessagingExtensionAttachment(HeroCard.ContentType, null, heroCard);
            var result = new MessagingExtensionResult("list", "result", new[] { attachments });

            return new MessagingExtensionResponse(result);
        }