I started implementing single sign on on my simple bot for practice. I already implemented it and can successfully authenticate the user using DirectLine with Enhanced Authentication. My problem was, every time I refresh the html where I render the webchat, the OAuth Card
always appear.
How do I prevent this specially when the user already authenticated?
Here is how I render the webchat in a static html file
<!DOCTYPE html>
<html>
<head>
<script src="https://cdn.botframework.com/botframework-webchat/latest/webchat.js"></script>
<style>
html,
body {
height: 100%;
}
body {
margin: 0;
}
#webchat {
height: 100%;
width: 100%;
}
</style>
</head>
<body>
<div id="webchat" role="main"></div>
<script>
(async function () {
// Set the CSS rules.
const styleSet = window.WebChat.createStyleSet({
bubbleBackground: '#F2F0F0',
bubbleBorderRadius: 10,
bubbleBorderStyle: 'solid',
bubbleBorderWidth: 1,
bubbleFromUserBackground: '#FDFDFD',
bubbleFromUserBorderRadius: 10,
bubbleFromUserBorderStyle: 'solid',
bubbleFromUserBorderWidth: 1,
rootHeight: '100%',
rootWidth: '100%',
backgroundColor: '#ffffff'
});
// After generated, you can modify the CSS rules.
// Change font family and weight.
styleSet.textContent = {
...styleSet.textContent,
fontFamily: "'Arial', 'Helvetica', sans-serif",
fontWeight: 'regular'
};
const avatarOptions = {
botAvatarInitials: 'BO',
userAvatarInitials: 'UR'
};
const res = await fetch('https://token-service.azurewebsites.net/api/directline/token');
const { token } = await res.json();
window.WebChat.renderWebChat({
directLine: window.WebChat.createDirectLine({ token }),
styleSet,
styleOptions: avatarOptions
}, document.getElementById('webchat'));
})().catch(err => console.error(err));
</script>
</body>
</html>
This my sample code snippet on my MainDialog
public class MainDialog : ComponentDialog
{
public MainDialog()
{
AddDialog(new OAuthPrompt(
nameof(OAuthPrompt),
new OAuthPromptSettings
{
ConnectionName = configuration["ConnectionName"],
Text = "Please Sign In",
Title = "Sign In",
Timeout = 300000
}));
AddDialog(new WaterfallDialog(nameof(WaterfallDialog), new WaterfallStep[]
{
InitialSignInStepAsync,
SignInStepAsync,
RepromptSignInStepAsync,
WelcomeStepAsync
}
InitialDialogId = nameof(WaterfallDialog);
}
private async Task<DialogTurnResult> InitialSignInStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
_logger.LogInformation("MainDialog - InitialSignInStepAsync");
return await stepContext.BeginDialogAsync(nameof(OAuthPrompt), null, cancellationToken);
}
private async Task<DialogTurnResult> SignInStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
_logger.LogInformation("MainDialog - SignInStepAsync");
var tokenResponse = (TokenResponse)stepContext.Result;
if (tokenResponse != null)
{
return await stepContext.NextAsync(null, cancellationToken);
}
await stepContext.Context.SendActivityAsync(MessageFactory.Text("Login was not successful please try again."), cancellationToken);
return await stepContext.EndDialogAsync();
}
private async Task<DialogTurnResult> RepromptSignInStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
_logger.LogInformation("MainDialog - RepromptSignInStepAsync");
// Call the prompt again because we need the token. The reasons for this are:
// 1. If the user is already logged in we do not need to store the token locally in the bot and worry
// about refreshing it. We can always just call the prompt again to get the token.
// 2. We never know how long it will take a user to respond. By the time the
// user responds the token may have expired. The user would then be prompted to login again.
//
// There is no reason to store the token locally in the bot because we can always just call
// the OAuth prompt to get the token or get a new token if needed.
return await stepContext.BeginDialogAsync(nameof(OAuthPrompt), null, cancellationToken);
}
private async Task<DialogTurnResult> WelcomeStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
_logger.LogInformation("MainDialog - WelcomeStepAsync");
if (stepContext.Result != null)
{
var tokenResponse = stepContext.Result as TokenResponse;
// Use the token to get user info using MSGraph
}
}
}