Teams Bot OAuthPrompt Not returning Tokenresponse for a couple of company members

Jasper Baetslé 80 Reputation points
2024-01-26T10:27:32.55+00:00

I have made and implemented a Teams bot for my company that is connected to a ASP.NET program on Azure but I am having some problems using the OAuthPrompt.

To give you some context and application insight: The endpoint is a BotController that allows Anonymous requests on /api/messages, this then uses the IBotFrameworkHttpAdapter and IBot to handle the request. My adapter is using base.Use(new TeamsSSOTokenExchangeMiddleware) to get SSO to work. In the IBot I override the method OnMessageActivityAsync to process incomming request. I first check if the user is trying to log out (mainly testing debugging purposes) and if not logout it tries to get the userToken, if this returns a succes, I will process the message which is working. If tokenResponse == null, I start a dialog for the authentication. In here I register an OAuthPrompt and a WaterfallDialog to process the authentication.

The services:

services.AddSingleton<BotFrameworkAuthentication, ConfigurationBotFrameworkAuthentication>();
services.AddSingleton<IBotFrameworkHttpAdapter, AdapterWithErrorHandler>();
services.AddTransient<MainDialog>();
services.AddTransient<IBot, TeamsBot<MainDialog>>();

and the main dialog:

public MainDialog(IConfiguration configuration, IMemoryCache memoryCache, ITeamsService teamsService)
{
    _memoryCache = memoryCache;
    _teamsService = teamsService;
    _configuration = configuration;
    AddDialog(new OAuthPrompt(
        nameof(OAuthPrompt),
        new OAuthPromptSettings
        {
            ConnectionName = configuration["ConnectionName"] ?? throw new ArgumentException("ConnectionName"),
            Text = "Please Sign In",
            Title = "Sign In",
            Timeout = 300000, // User has 5 minutes to login (1000 * 60 * 5)
            EndOnInvalidMessage = true
        }));

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

    // The initial child Dialog to run.
    InitialDialogId = nameof(WaterfallDialog);
}

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

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;
    String? question;
    _memoryCache.TryGetValue(stepContext.Context.Activity.From.Id, out question);
    if (tokenResponse == null)
    {
        Console.WriteLine($"LoginStepAsync: tokenResponse is null, question={question ?? "question is leeg"}");
    } else
    {
        Console.WriteLine($"LoginStepAsync: question={question ?? "question is leeg"}, fromId: {stepContext.Context.Activity.From.Id}, tokenResponse: {tokenResponse.ConnectionName} / {tokenResponse.ChannelId} / {tokenResponse.Expiration}, hasToken: {tokenResponse.Token != null}");
        Console.WriteLine($"LoginStepAsync: fromId={stepContext.Context.Activity.From.Id}");
        Console.WriteLine($"LoginStepAsync: tokenResponse.ConnectionName={tokenResponse.ConnectionName}");
        Console.WriteLine($"LoginStepAsync: tokenResponse.ChannelId={tokenResponse.ChannelId}");
        Console.WriteLine($"LoginStepAsync: tokenResponse.Expiration={tokenResponse.Expiration}");
        Console.WriteLine($"LoginStepAsync: hasToken={tokenResponse.Token != null}");
        Console.WriteLine($"LoginStepAsync: tokenResponse.Properties={tokenResponse.Properties?.ToString() ?? "null"}");
    }
    if (tokenResponse?.Token != null && question != null)
    {
        await _teamsService.ProcessTeamsMessageAsync(stepContext.Context, question, tokenResponse.Token, cancellationToken);
    }
    else
    {
        await stepContext.Context.SendActivityAsync(MessageFactory.Text("Stuur je vraag nogmaals aub."), cancellationToken);
        return await stepContext.BeginDialogAsync(nameof(OAuthPrompt), null, cancellationToken);
    }

    return await stepContext.EndDialogAsync(cancellationToken: cancellationToken);
}
protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
    var userTokenClient = turnContext.TurnState.Get<UserTokenClient>();

    if (turnContext.Activity.Text.Equals("logout"))
    {
        await userTokenClient.SignOutUserAsync(turnContext.Activity.From.Id, _connectionName, turnContext.Activity.ChannelId, cancellationToken: cancellationToken);
        await turnContext.SendActivityAsync(MessageFactory.Text("You have been signed out."), cancellationToken);
        return;
	}

    var tokenResponse = await userTokenClient.GetUserTokenAsync(turnContext.Activity.From.Id, _connectionName, turnContext.Activity.ChannelId, null, cancellationToken).ConfigureAwait(false);

	if (tokenResponse == null)
	{
        _memoryCache.Set(turnContext.Activity.From.Id, turnContext.Activity.Text, TimeSpan.FromMinutes(5));
		await _dialog.RunAsync(turnContext, _conversationState.CreateProperty<DialogState>(nameof(DialogState)), cancellationToken);
		return;
	}

	await _teamsService.ProcessTeamsMessageAsync(turnContext, turnContext.Activity.Text, tokenResponse.Token, cancellationToken);
}

As you can see in the image, the user tries to logout, and when sending the next message it fails, when trying to send it again it keeps giving the message Stuur je vraag nogmaals aub. When trying this as another user, everything works fine and the message to resend the question never shows. I checked Entra ID and there are no specific groups that are different. When I send the person a direct connection link (the one provided in the azure bot configuration), it instantly shows the token without login. [![enter image description here][1]][1]

Is there anything I am missing or doing wrong with the dialog stuff? Please let me know if you need any extra information!

EDIT

As someone else also pointed out, they also get this problem with the quick start sample project. Someone from Microsoft should really look into this. Where do I file a bug report? [1]: https://i.stack.imgur.com/vFuaz.png

Microsoft Teams
Microsoft Teams
A Microsoft customizable chat-based workspace.
9,978 questions
Microsoft Teams Development
Microsoft Teams Development
Microsoft Teams: A Microsoft customizable chat-based workspace.Development: The process of researching, productizing, and refining new or existing technologies.
3,207 questions
0 comments No comments
{count} vote

1 answer

Sort by: Most helpful
  1. Eduardo Oliveira 0 Reputation points
    2024-01-31T15:29:38.8033333+00:00

    I have the same problem with the quick start sample project.


Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.