category
In this demo, we will show you how to authorize a user to access resources on an enterprise app with a bot. Two types of resources are used to demonstrate the interoperability of OAuth: Microsoft Graph and GitHub API.
When dealing with personal data, please respect user privacy. Follow platform guidelines and post your privacy statement online.
Different companies may use different access delegation technologies to protect their resources. In our demo, we are targeting authorization through OAuth 2.0).
Although OAuth and OpenID are often related to each other, they solve different problems. OAuth is for authorization and access delegation, while OpenID is for authentication and user identity.
Instead of OpenID, most enterprise apps use OAuth plus a user profile API to identify an individual user. In this demo, we will demonstrate how to use OAuth to obtain access to user profile API and use the API to identifying the accessor.
This demo does not include any threat models and is designed for educational purposes only. When you design a production system, threat-modelling is an important task to make sure your system is secure and provide a way to quickly identify potential source of data breaches. IETF RFC 6819 and OAuth 2.0 for Browser-Based Apps is a good starting point for threat-modelling when using OAuth 2.0.
This demo integrates with multiple services. There are multiple services you need to setup in order to host the demo.
- Clone the code
- Setup OAuth via GitHub
- Setup OAuth via Azure Active Directory
- Setup Azure Bot Services
- Prepare and run the code
To host this demo, you will need to clone the code and run locally.
- Clone this repository
- Create two files for environment variables,
/bot/.envand/rest-api/.env
- In
/rest-api/.env:
- Write
AAD_OAUTH_REDIRECT_URI=http://localhost:3000/api/aad/oauth/callback
- When Azure Active Directory completes the authorization flow, it will send the browser to this URL. This URL must be accessible by the browser from the end-user machine
- Write
GITHUB_OAUTH_REDIRECT_URI=http://localhost:3000/api/github/oauth/callback
- Same as Azure Active Directory, this is the URL for GitHub to send its result
- Write
- In
If you want to authenticate on GitHub, follow the steps below.
- Sign into GitHub and create a new OAuth application
- Browse to https://github.com/settings/developers
- Select "OAuth Apps"
- Click "New OAuth App" button
- Fill out "Application name" and "Homepage URL", for example, "Web Chat SSO Sample"
- The "Application name" and "Homepage URL" will be shown to the user when they authorize your GitHub OAuth app
- In "Application callback URL", enter
http://localhost:3000/api/github/oauth/callback - Click "Register application"
- Save the "Client ID" and "Client Secret" to
/rest-api/.env
GITHUB_OAUTH_CLIENT_ID=a1b2c3dGITHUB_OAUTH_CLIENT_SECRET=a1b2c3d4e5f6
If you want to authenticate on Azure Active Directory, follow the steps below.
- Go to your Azure Active Directory
- Create a new application
- Select "App registrations"
- Click "New registration"
- Fill out "Name", for example, "Web Chat SSO Sample"
- In "Redirect URI (optional)" section, add a new entry
- Select "Public client (mobile & desktop)" as type
- Instead of client secret, we are using PKCE (RFC 7636) to exchange for authorization token, thus, we need to set it to "Public client" instead of "Web"
- Enter
http://localhost:3000/api/aad/oauth/callbackas the redirect URI
- This must match
AAD_OAUTH_REDIRECT_URIin/rest-api/.envwe saved earlier
- This must match
- Select "Public client (mobile & desktop)" as type
- Click "Register"
- Save the client ID
- Select "Overview"
- On the main pane, copy the content of "Application (client) ID" to
/rest-api/.env, it should looks be a GUID
AAD_OAUTH_CLIENT_ID=12345678abcd-1234-5678-abcd-12345678abcd
We prefer using Bot Channel Registration during development. This will help you diagnose problems locally without deploying to the server and speed up development.
You can follow our instructions on how to setup a new Bot Channel Registration.
- Save the Microsoft App ID and password to
/bot/.env
MICROSOFT_APP_ID=12345678-1234-5678-abcd-12345678abcdMICROSOFT_APP_PASSWORD=a1b2c3d4e5f6
- Save the Web Chat secret to
/rest-api/.env
DIRECT_LINE_SECRET=a1b2c3.d4e5f6g7h8i9j0
When you are building your production bot, never expose your Web Chat or Direct Line secret to the client. Instead, you should use the secret to generate a limited token and send it to the client. For information, please refer to this page on how to generate a Direct Line token and Enhanced Direct Line Authentication feature.
During development, you will run your bot locally. Azure Bot Services will send activities to your bot through a public URL. You can use ngrok to expose your bot server on a public URL.
- Run
ngrok http -host-header=localhost:3978 3978 - Update your Bot Channel Registration. You can use Azure CLI or Azure Portal
- Via Azure CLI
- Run
az bot update --resource-group <your-bot-rg> --name <your-bot-name> --subscription <your-subscription-id> --endpoint "https://a1b2c3d4.ngrok.io/api/messages"
- Run
- Via Azure Portal
- Browse to your Bot Channel Registration
- Select "Settings"
- In "Configuration" section, set "Messaging Endpoint" to
https://a1b2c3d4.ngrok.io/api/messages
- Via Azure CLI
- Under
app,bot, andrest-apifolder, run the following:
npm installnpm start
- Browse to http://localhost:3000/ to start the demo
- Notice there are two sign-in buttons on top-right hand corner
- After signed in, both the website and the bot get your sign in information
- Type, "where are my packages" in Web Chat
- If not signed in, the bot will present a sign-in button
- If signed in, the bot will answer the question
- Type, "bye" in Web Chat
- If signed in, the bot will sign you out
/app/is the React app built usingcreate-react-appscaffold/bot/is the bot server/rest-api/is the REST API for handling OAuth requests
GET /api/aad/oauth/authorizewill redirect to Azure AD OAuth authorize page at https://login.microsoftonline.com/12345678-1234-5678-abcd-12345678abcd/oauth2/v2.0/authorizeGET /api/aad/oauth/callbackwill handle callback from Azure AD OAuthGET /api/aad/settingswill send Azure AD OAuth settings to the React appGET /api/directline/tokenwill generate a new Direct Line token for the React appGET /api/github/oauth/authorizewill redirect to GitHub OAuth authorize page at https://github.com/login/oauth/authorizeGET /api/github/oauth/callbackwill handle callback from GitHub AD OAuthGET /api/github/settingswill send GitHub OAuth settings to the React app- It will serve React app as a static content
- During development-time, it will also serve the bot server via
/api/messages
- To enable this feature, add
PROXY_BOT_URL=http://localhost:3978to/web/.env - This will forward all traffic from
https://a1b2c3d4.ngrok.io/api/messagestohttps://localhost:3978/api/messages
- To enable this feature, add
This sample includes multiple parts:
- A basic web page with sign in and sign out button, coded with React
- Web Chat integrated, coded with pure JavaScript
- Wiring between the web page and Web Chat through DOM events
- When web page sign in, it should emit DOM event
accesstokenchangewith{ data: { accessToken, provider } } - When the bot ask for sign in, Web Chat will emit DOM event
signinwith{ data: { provider: 'aad/github' } } - When the bot ask for sign out, Web Chat will emit DOM event
signout
- When web page sign in, it should emit DOM event
- For bot, OAuth access token is piggybacked on every user-initiated activity through
channelData.oauthAccessTokenandchannelData.oauthProvider
- Developer has an existing enterprise web app that uses OAuth to access protected resources
- We assume the OAuth access token lives in the browser's memory and is accessible through JavaScript
- Access token can live in browser memory but must be secured during transmit through the use of TLS
- More about security considerations can be found at IETF RFC 6749 Section 10.3
- We assume the OAuth access token lives in the browser's memory and is accessible through JavaScript
- Developer know how to alter existing JavaScript code around their existing UI for OAuth
- Website and bot conversation supports both anonymous and authenticated access
- Forced page refresh and/or new conversation is not mandated
- End-user is able to sign in through the web page, and is recognized by the bot immediately
- Vice versa, end-user is able to sign in through the bot, and is recognized by the web page immediately
- End-user is able to sign in through the web page and sign out though the bot
- Vice versa, end-user is able to sign in through the bot and sign out through the web page
In our demo, we built an enteprise single-page app using React. Then, we use a <script> tag to embed Web Chat. This is for separating the code so developers reading this sample can study the changes and easily understand the interactions between them.
You are not required to code your web app in React or use Web Chat via <script> tag. In fact, you can write both your web app and embed Web Chat using either pure JavaScript or React.
Since the demo is running in a heterogeneous environment (both React and pure JavaScript), additional wire-ups are required. We use DOM events to wire up the enterprise app (authentication UI) and Web Chat.
In your production system, since you are probably in a homogenous environment (either React or pure JavaScript), you may want to use Redux or other mechanisms to wire up different UI components.
This demo is coded in heterogeneous environment. Web Chat code is written in pure JavaScript, and the website is written in React. This makes the Web Chat integration code easier to extract from the webpage code.
The .env files hold the environment variables critical to run the service. These are usually security-sensitive information and must not be committed to version control. Although we recommend keeping these keys in Azure Vault, for simplicity of this sample, we would keep them in .env files.
To ease the setup of this sample, here is the template of .env files.
MICROSOFT_APP_ID=12345678-1234-5678-abcd-12345678abcd
MICROSOFT_APP_PASSWORD=a1b2c3d4e5f6
AAD_OAUTH_CLIENT_ID=12345678abcd-1234-5678-abcd-12345678abcd
AAD_OAUTH_REDIRECT_URI=http://localhost:3000/api/aad/oauth/callback
DIRECT_LINE_SECRET=a1b2c3.d4e5f6g7h8i9j0
GITHUB_OAUTH_CLIENT_ID=a1b2c3d
GITHUB_OAUTH_CLIENT_SECRET=a1b2c3d4e5f6
GITHUB_OAUTH_REDIRECT_URI=http://localhost:3000/api/github/oauth/callback
In this sample, we do not use OAuth card due to technical limitations on some OAuth providers which support single redirect URI only.
In order to use the website to sign in, the developer will need to set the redirect URI to their own web API.
In order to use the bot to sign in, in the OAuth provider, the developer will need to set the redirect URI to https://token.botframework.com/.auth/web/redirect.
Since some OAuth providers do not support multiple redirect URIs, we prefer using a single redirect URI from the web API to make sure existing authorization flow is not disturbed.
After having signed in on this app, click the profile photo on the upper-right hand corner, select "Review access on Office.com" or "Review access on GitHub". Then, you will be redirected to the OAuth provider page to remove your authorization.
- For GitHub, you can click the "Revoke access" button
- For Azure Active Directory
- On the AAD dashboard page, wait until "App permissions" loads. Here you see how many apps you have authorized
- Click "Change app permissions"
- In the "You can revoke permission for these apps" section, click the "Revoke" button below your app registration
- RFC 6749: The OAuth 2.0 Authorization Framework
- RFC 6819: OAuth 2.0 Threat Model and Security Considerations
- RFC 7636: Proof Key for Code Exchange by OAuth Public Clients
- IETF Draft: OAuth 2.0 for Browser-Based Apps
- Bot Framework Blog: Enhanced Direct Line Authentication feature
To make this demo simpler to understand, instead of refresh token, we are obtaining the access token via Authorization Code Grant flow. Access token is short-lived and considered secure to live inside the browser.
In your production scenario, you may want to obtain the refresh token with "Authorization Code Grant" flow instead of using the access token. We did not use the refresh token in this sample as it requires server-to-server communications and secured persistent storage, it would greatly increase the complexity of this demo.
To reduce complexity, this sample is limited in scope. In your production system, you should consider enhancing it and review its threat model.
- Refreshing the access token
- Using silent prompt for refreshing access token
- Some OAuth providers support
?prompt=nonefor refreshing access token silently through<iframe>
- Some OAuth providers support
- Using Authorization Code Grant flow with refresh token
- Save the refresh token on the server side of your web app. Never expose it to the browser or the bot
- This will also create a smooth UX by reducing the need for UI popups
- Using silent prompt for refreshing access token
- Threat model
- IETF RFC 6819 is a good starting point for threat-modelling when using OAuth 2.0
To lower the barrier for the end-user to initiate a conversation with the bot, in this sample, the conversation can be both anonymous or authenticated.
That means at some points of time, the mixed conversation can be authenticated as different users. If it is not a desirable scenario for your use case, you might want to create a new conversation if the user signed out.
- 登录 发表评论
- 8 次浏览
最新内容
- 1 week 3 days ago
- 1 week 3 days ago
- 1 month ago
- 1 month ago
- 1 month ago
- 1 month ago
- 1 month ago
- 1 month ago
- 1 month ago
- 1 month ago