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

Jasper Baetslé 120 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 | Development
Microsoft Teams | Development
Building, integrating, or customizing apps and workflows within Microsoft Teams using developer tools and APIs
Microsoft Teams | Microsoft Teams for business | Other
0 comments No comments
{count} vote

1 answer

Sort by: Most helpful
  1. Anonymous
    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' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.