I tried implementing the sample code for OAuthInput, but the TokenProperty property doesn't seem to exist on class OAuthInput. It would also be nice to have some documentation on how OAuthInput should be implemented in broader sense. As in: how do I ge the token in later steps, is this token automatically refreshed when it expires? What happens when the token in time is not valid any more? I was unable to find up-to-date documentation on this for the Adaptive Dialog.
⚠Do not edit this section. It is required for docs.microsoft.com ➟ GitHub issue linking.
@jsiegmund Please, look at this article: Authentication. It might help in handling the token expiration.
@jsiegmund As far as OAuthInput is concerned , waiting for an official sample, you can look at this proof of concept below to get an idea.
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.Dialogs.Adaptive;
using Microsoft.Bot.Builder.Dialogs.Adaptive.Actions;
using Microsoft.Bot.Builder.Dialogs.Adaptive.Conditions;
using Microsoft.Bot.Builder.Dialogs.Adaptive.Generators;
using Microsoft.Bot.Builder.Dialogs.Adaptive.Input;
using Microsoft.Bot.Builder.Dialogs.Adaptive.Templates;
using Microsoft.Bot.Builder.LanguageGeneration;
using Microsoft.Extensions.Configuration;
using System.Collections.Generic;
using System.IO;
namespace AdaptiveOAuthBot.Dialogs
{
public class RootDialog : AdaptiveDialog
{
private OAuthInput MyOAuthInput { get; }
public RootDialog(IConfiguration configuration) : base(nameof(RootDialog))
{
MyOAuthInput = new OAuthInput
{
ConnectionName = configuration["ConnectionName"],
Title = "Please log in",
Text = "This will give you access!",
InvalidPrompt = new ActivityTemplate("Login was not successful please try again."),
Timeout = 300000,
MaxTurnCount = 3,
Property = "turn.oauth",
};
string[] paths = { ".", "Dialogs", $"RootDialog.lg" };
string fullPath = Path.Combine(paths);
// These steps are executed when this Adaptive Dialog begins
Triggers = new List<OnCondition>
{
// Add a rule to welcome user
new OnConversationUpdateActivity
{
Actions = WelcomeUserSteps(),
},
// Respond to user on message activity
new OnUnknownIntent
{
Actions = LoginSteps(),
},
};
Generator = new TemplateEngineLanguageGenerator(Templates.ParseFile(fullPath));
}
private static List<Dialog> WelcomeUserSteps()
{
return new List<Dialog>
{
// Iterate through membersAdded list and greet user added to the conversation.
new Foreach()
{
ItemsProperty = "turn.activity.membersAdded",
Actions =
{
// Note: Some channels send two conversation update events - one for the Bot added to the conversation and another for user.
// Filter cases where the bot itself is the recipient of the message.
new IfCondition()
{
Condition = "$foreach.value.name != turn.activity.recipient.name",
Actions =
{
new SendActivity("Hello, I'm the multi-turn prompt bot. Please send a message to get started!")
}
}
}
}
};
}
private List<Dialog> LoginSteps()
{
return new List<Dialog>
{
MyOAuthInput,
//new SendActivity("\\{turn.token.token} = `${turn.token.token}`."),
new IfCondition
{
Condition = "turn.token.token && length(turn.token.token)",
Actions = LoginSuccessSteps(),
ElseActions =
{
new SendActivity("Sorry, we were unable to log you in."),
},
},
new EndDialog(),
};
}
private List<Dialog> LoginSuccessSteps()
{
return new List<Dialog>
{
new SendActivity("You are now logged in."),
new ConfirmInput
{
Prompt = new ActivityTemplate("Would you like to view your token?"),
InvalidPrompt = new ActivityTemplate("Oops, I didn't understand. Would you like to view your token?"),
MaxTurnCount = 3,
},
new IfCondition
{
Condition = "turn.lastResult == true",
ElseActions =
{
new SendActivity("Great. Type anything to continue."),
},
Actions =
{
MyOAuthInput,
new SendActivity("Here is your token `${turn.token.token}`."),
},
},
};
}
}
}
Yeah I had it working in the meantime, but ran into another problem in MS Teams (see https://github.com/microsoft/botbuilder-dotnet/issues/4477). So I got it 'working', but still the docs should be checked I think :)
@jsiegmund @Jeffders A couple of remarks to conclude this phase of the discussion.
MyOAuthInput = new OAuthInput
{
ConnectionName = configuration["ConnectionName"],
Title = "Please log in",
Text = "This will give you access!",
InvalidPrompt =
new ActivityTemplate("Login was not successful please try again."),
Timeout = 300000,
MaxTurnCount = 3,
Property = "turn.oauth",
};
defines the OAuthInput object that contains OAuth information. Property contains the memory path where to store the TokenResponse object.
The value shown in the example turn.oauth is arbitrary, you can use any value. It is a good practice to record the token response to a property on the turn scope, since the token can expire between turns.
Understood. In my current code I'm starting off the dialog with the OAuthInput, so I guess that when the dialog itself expires this would mean the user will have to instruct the bot to start the process again and would be faced with the OAuthInput again, right? That's fine with me.
As for the expired token itself, what I'm doing right now:
OAuthInput dialog stored in my main dialog. OAuthDialog.GetUserTokenAsync(context);In my debug sessions this works fine and I can do stuff for several minutes without having any expiry issues. But I've yet to test what happens when it starts taking too long. I'll need to check the expiry time of the token I'm getting back, otherwise a simple solution might be to have the same expiry time for the dialog itself so that it always expires even before the token does. The process I'm implementing is not something the user will be pauzing in most likely. Then again, it's still chat and chat is async of course.
@jsiegmund Can we close this issue? Thanks
My issue is fixed, but the error in the docs (TokenPropery instead of Property) is still there. So be my guest if you want to close it but I think it should be corrected nevertheless.
@jsiegmund That is what I need to know. Let me keep this open, for now. I will pass the info to the writer that is working on the specific documentation.
@jsiegmund The problem has been fixed and the updated documentation will be available in the next upcoming release.