2
votes

I have a Microsoft Teams bot and I am trying to authenticate the user using AAD (v2 endpoint). The bot uses V4 SDK and OauthPrompt.I am able to log in but unable to get the token.

I am using OAuth Card. The card is being rendered inside Teams. When the sign in button is clicked it goes to the Microsoft login page. After the user logins, the bot stops responding and hence I have no way to get the token.

The samples I am trying out are : https://github.com/microsoft/BotBuilder-Samples/tree/master/samples/csharp_dotnetcore/18.bot-authentication and https://github.com/microsoft/BotBuilder-Samples/tree/master/samples/csharp_dotnetcore/24.bot-authentication-msgraph.

Both the samples are working inside the emulator.

Here is the code fragment:

               AddDialog(new OAuthPrompt(
            nameof(OAuthPrompt),
            new OAuthPromptSettings
            {
                ConnectionName = ConnectionName,
                Text = "Please Sign In",
                Title = "Sign In",
                Timeout = 300000, // User has 5 minutes to login (1000 * 60 * 5)
            }));


         AddDialog(new ConfirmPrompt(nameof(ConfirmPrompt)));

        AddDialog(new WaterfallDialog(nameof(WaterfallDialog), new WaterfallStep[]
        {
            PromptStepAsync,
            LoginStepAsync,
            DisplayTokenPhase1Async,
            DisplayTokenPhase2Async,
        }));

 private async Task<DialogTurnResult> PromptStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
           return await stepContext.BeginDialogAsync(nameof(OAuthPrompt), null, cancellationToken);
        }


It never reaches the code:

        private async Task<DialogTurnResult> LoginStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
    {
        // Get the token from the previous step. Note that we could also have gotten the
        // token directly from the prompt itself. There is an example of this in the next method.
        var tokenResponse = (TokenResponse)stepContext.Result;
        if (tokenResponse != null)
        {
            await stepContext.Context.SendActivityAsync(MessageFactory.Text("You are now logged in."), cancellationToken);
            return await stepContext.PromptAsync(nameof(ConfirmPrompt), new PromptOptions { Prompt = MessageFactory.Text("Would you like to view your token?") }, cancellationToken);
        }

        await stepContext.Context.SendActivityAsync(MessageFactory.Text("Login was not successful please try again."), cancellationToken);
        return await stepContext.EndDialogAsync(cancellationToken: cancellationToken);
    }

I expected that the token would be received in the code once the user signs in, but the bot just stops responding.

2
Are you debugging your bot locally? Once Sign In pop-up is closed, it it hitting your bot endpoint?Wajeed-MSFT
@Wajeed-MSFT Yes, I am debugging it locally. It's hitting the bot controller and then the AuthBot constructor. But it never hits OnTokenResponseEventAsync method. When tested inside the emulator. I get the token and after entering the magic code, it displays a successful login messageGeethu Suresh
Could you please check if you are getting activity.Name = signin/verifyState? If yes then you need to handle the login completion activity. This ensures that the authentication request and the token are associated with the user currently interacting with your bot. Please have a look at Sample code in documentation.Wajeed-MSFT
I had used ** activity.Name = signin/verifyState ** for V3 bot. I am not sure on where to handle the login complete activity.The sample provides the code for V3 .Should I handle it inside **onTurnAsync ** method? And what about onTokenResponseEventAsync method?Geethu Suresh
@Wajeed-MSFT Also is it possible to get the token without going to the waterfall step ?Geethu Suresh

2 Answers

2
votes

It seems like this is a bug in the Bot framework, but there is already a pull request to fix this issue. You can find the pull request here.

Edit: They edited both authentication samples to fix this problem right now as you can see here.

0
votes

This is how I got it working.

public override async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
    {

        await base.OnTurnAsync(turnContext, cancellationToken);

        // Save any state changes that might have occured during the turn.
        await ConversationState.SaveChangesAsync(turnContext, false, cancellationToken);
        await UserState.SaveChangesAsync(turnContext, false, cancellationToken);

           if (turnContext.Activity.Name == "signin/verifyState")
            {

                await Dialog.Run(turnContext, ConversationState.CreateProperty<DialogState>(nameof(DialogState)), cancellationToken);

            }

      }

It then goes to LoginStepAsync step of Waterfall.