category
This sample demonstrates how to implement Web Chat in a way that (a) does not expose your Direct Line secret to the browser, and (b) ensures your bot will receive a consistent and trustworthy user ID across sessions. Specifically, it shows how to retrieve a user-specific Direct Line token for a user who has been verified by an identity provider.
In the Direct Line token sample, in order to hide the Web Chat secret and avoid user impersonation, we bound a random user ID to the Direct Line token. The downside of that approach is that users will have a different ID every time they talk to the bot. We could improve on this by storing a user ID in client-side storage (cookie, localStorage
, etc.) and sending it to the token API, but there would still be two issues:
- The user ID would be tied to the browser and wouldn't be consistent across browsers, devices, etc.
- A malicious user could modify their user ID to attempt to impersonate a different user, so the bot wouldn't be able to trust the user ID.
A better approach is to leverage a user's existing identity from a true identity provider. The user must first sign in to the site before talking to the bot. Then, if the user signs in using the same identity on a different browser or device, the user ID will be the same. This also prevents user impersonation because we can verify the user's identity with the identity provider instead of blindly trusting the user ID.
This sample contains three components:
- The backend API performs the Direct Line token acquisition. It verifies the user's identity and then acquires a Direct Line token that is bound to that identity.
- The UI is static HTML/JS that could be hosted using any web server. It requires the user to sign in, then makes a request to the backend API with proof of the user's identity. It uses the resulting Direct Line token to render Web Chat.
- The bot is a bare-bones bot that responds to every activity by sending the user's ID.
The interesting component is the backend API, which goes through the following steps:
- In the body of the POST request to the API, receive an OpenID Connect (OIDC) JWT (called an ID token) that identifies the user.
- Validate the ID token against the chosen identity provider (AAD in this sample).
- Build a user ID using claims from the validated token. We chose to use the
sub
(subject) claim because it's a standard OIDC claim that uniquely identifies the user, and it doesn't require any additional scopes.
- In AAD, the
sub
claim is only consistent per user per application. This means our user ID wouldn't be sufficient for looking up the user in other systems (such as Microsoft Graph). If we needed a user ID that identifies the user across applications, we could use theoid
(object ID) claim, but it requires theprofile
scope. See AAD ID token claims for more details. - Since the user identity is verified, it is okay for this user ID to be a "guessable" value.
- In AAD, the
- Retrieve a user-specific Direct Line token using the Direct Line API.
- Respond with the user-specific Direct Line token.
Depending on the scenario, the backend API could be called from a client (such as a single-page application) or a server (such as a more traditional web app, where tokens are handled server-side). The only requirement is that the caller can provide an ID token from the expected identity provider. If you are embedding the bot in an authenticated site, then you may already have an ID token that you can use.
After receiving the Direct Line token, the caller can then use it to render Web Chat, and the bot will receive a consistent user ID that it can rely on.
The API expects the ID token to be passed in the request body:
JavaScript
C#
Tokens are typically sent as bearer tokens in the Authorization
header. However, we aren't using the user's ID token to protect the API. Rather, it is a parameter of the request itself. Although the API isn't protected in this sample, you could protect the API using a different token (such as an OAuth access token) which would go in the Authorization
header.
JavaScript
C#
In this sample, we directly use the sub
claim of the token as the user ID:
JavaScript
C#
You could customize this to use different claims depending on your needs. See Architecture for an explanation of why we chose the sub
claim.
The API calls the Direct Line API to retrieve a Direct Line token. Notice that we pass the user ID in the body of the request:
JavaScript
C#
The resulting Direct Line token will be bound to the passed user ID.
After the user signs in, the UI calls the API with the user's ID token and uses the resulting Direct Line token to render Web Chat:
// index.html
async function getDirectLineToken(idToken) {
const res = await fetch('http://localhost:3000/api/direct-line-token', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ id_token: idToken }),
});
...
return await res.json();
}
...
const directLineTokenResponse = await getDirectLineToken(idToken);
...
WebChat.renderWebChat(
{
directLine: WebChat.createDirectLine({ token: directLineTokenResponse.token }),
},
document.getElementById('webchat')
);
Note that we do not specify a user ID when initiating Web Chat. Direct Line will handle sending the user ID to the bot based on the token.
- A registered Bot Framework bot (see documentation on registering a bot with Azure Bot Service)
Since the user will be signing in to the web app using AAD, we must register an AAD application. See the docs for registering an AAD application or follow these steps:
- Sign in to the Azure portal and find the Azure Active Directory section.
- In App registrations, click New registration and fill in the following details:
- Name: A meaningful display name, like "Direct Line Token Sample"
- Supported account types: Accounts in any organizational directory (Any Azure AD directory - Multitenant) and personal Microsoft accounts (e.g. Skype, Xbox)
- Redirect URI: Select Web and enter
http://localhost:5500
- Click Register.
- In the Overview blade, copy the Application (client) ID. We will use this later.
- In the Authentication blade, under Implicit grant, check the box for ID tokens and click Save.
- Navigate to the
bot
directory. - Fill in the environment variables in the
.env
file, according to the following table:
Variable Description Example value PORT
The port on which the bot server will run. 3978 MICROSOFT_APP_ID
The app ID of the registered Bot Framework bot. Can be found in the Azure Bot Channels Registration resource. MICROSOFT_APP_SECRET
The app secret of the registered Bot Framework Bot. Issued during registration. - Run
npm install
to install the required dependencies. - Run
npm start
to start the bot. -
Run
ngrok
to expose your bot to a public URL. For example:ngrok http -host-header=rewrite 3978
- Update the messaging endpoint in your Bot Channels Registration to the ngrok URL. For example:
https://abcdef.ngrok.io/api/messages
The sample API is available in multiple languages. Choose one and expand the corresponding section for specific steps.
JavaScript API
C# API
-
Navigate to the
ui
directory. -
Open
index.html
in an editor, find the empty variables at the top of thescript
tag, and fill in the values according to the following table:Variable Description Example value AAD_APP_ID
The client ID of the AAD app created above. 34d690a0-a2fb-4163-9dde-404105d88c30 AAD_REDIRECT_URI
The redirect URI registered in the AAD app created above. http://localhost:5500 -
Serve
index.html
onlocalhost:5500
using a web server.-
A quick way to get started is using the http-server npm package. You can use
npx
to run it without installation:npx http-server ./ -p 5500
- Another option is a local development server such as the Live Server Visual Studio Code extension.
-
-
Open
http://localhost:5500
in a browser and sign in.
- Although this sample uses AAD, you can achieve the same result using a different identity provider.
- 登录 发表评论
- 2 次浏览
Tags
最新内容
- 3 days 4 hours ago
- 3 days 4 hours ago
- 3 days 4 hours ago
- 3 days 4 hours ago
- 4 days 9 hours ago
- 1 week 5 days ago
- 1 week 5 days ago
- 1 week 5 days ago
- 2 weeks 1 day ago
- 2 weeks 1 day ago