Search for your SharePoint content from a bot using the Bot Framework, OAuth2 and Node.js

Search for your SharePoint content from a bot using the Bot Framework, OAuth2 and Node.js

In this post, I’ll show you how to search for your SharePoint content from a bot using the Bot Framework, OAuth2 and Node.js. Behind this simple use case, the main objective of this example is to show you how to implement a bot with an authentication mechanism to access OAuth2 protected APIs (like SharePoint, Graph, etc.). The overall authentication process for bots has already been well described in this article but unfortunately, it only exists in .Net (there is also the AuthBot GitHub project, again in .Net). The complete code of the current sample (Node.js) is available here:

And the final result:

Web chat


Microsoft Teams

This solution leverages the “Sign-In card” feature of the Bot Framework. Now, let’s see how to do this:

Step 1: Configure the Azure AD Application

First of all, to give access to SharePoint Online you need to configure a new application within the Azure tenant hidden behind your Office 365 subscription. To access it, you have to sign-up in the Azure Portal using your Office 365 information. Then you will be able to manage your Azure Active Directory behind Office 365.

Go to your Active Directory and add a new application.

Generate keys and save the client Secret (i.e keys) and the client Id. Then enter the following information:

    1. APP ID URI: your Office 365 tenant URL like
    2. REPLY URL: Leave blank for now.

Under the permissions section, add a new application and select “Office 365 SharePoint Online“:

Then, under the “Delegated permissions“, select “Read items in all site collections“. That’s the only permission we need to perform SharePoint search queries:

Step 2: Create the Node.js application

To implement the bot logic, we use a Node.js application. The code is available here. Here are some key points of this solution to better understand the implementation:

Using a dedicated Node.js application instead of the Azure Bot Service

You may have noticed that a Bot service is available in preview within Azure. It creates a complete environement for a bot using some starter templates (LUIS bot, Proactive bot ,etc.). Behind the scenes, an Azure function is used to implement the bot logic. In our scenario, we need a callback URL to perform the OAuth2 flow and get the authorization code (the REPLY URL in the Azure AD App). Because Azure functions are based on a serverless architecture, they can’t be used for this specific purpose so that’s why we use a dedicated web application for this (an Azure function doesn’t have a route system and have only a single end point, already used for the bot dialog via the /api/messages route).

The OAuth2 flow implementation

To help us implementing the OAuth2 flow, we use the adal-node npm module especially to:

  • Get an access token from an authorization code. The authorization code is retrieved “manually” via the /oauth-callback handler according to the REPLY URL set in the AAD App. Also, the sign-in process is initiated from the bot through a “Sign-In” card (wich is a simple link that redirects to a preconfigured authorization URL).
  • Get an access token from a refresh token (when the access token is expired).

As a reminder, here are the OAuth2 behavior with Azure AD. Before using this solution, you must fill the correct information of your tenant and SharePoint environment in the server.js file:

To see all query string parameters, please refer to this url.

Get the authorization code and get back to the bot dialog

This is clearly the tricky part. When receiving the autorization code, you have to get back to the previous state of your bot to continue the conversation with the current user. To do this, according to the Bot Framework documentation, you have to save the session address containing all the information about the current conversation by serializing it. But how save this information during the authorization process? The answer is: the “state” parameter of the OAuth2 protocol (thanks to this blog post to had me point out the solution).

The primary function of this parameter is to prevent CRSF attacks but it can also be used to save the bot state as well. So when we build the authorization URL, we serialize the address in the state query string parameter:

According to the OAuth2 specifications, this parameter is sent back as is by the authorization server so we can then deserialize it and continue the dialog for the current user via the bot.beginDialog() method:

Notice that there are some differences between bot.send() and bot.beginDialog() (see the “Starting Conversations” paragraph in the documentation).

Save the access token for the current user in the bot state

Because we have to provide a valid access token every time we want to perform an authenticated call on the SharePoint REST API, we must save it for each user. To do this, we use the Bot State Service. According to the documentation of the Node.js BotBuilder, the following properties can be used to persist data for a user or a conversation within the bot state:

Field Use Cases
userData Stores information globally for the user across all conversations.
conversationData Stores information globally for a single conversation. This data is visible to everyone within the conversation so care should be used to what’s stored there. It’s disabled by default and needs to be enabled using the bots persistConversationData setting.
privateConversationData Stores information globally for a single conversation but its private data for the current user. This data spans all dialogs so it’s useful for storing temporary state that you want cleaned up when the conversation ends.
dialogData Persists information for a single dialog instance. This is essential for storing temporary information in between the steps of a waterfall.

In this sample, we want every users to have their own access token so that’s why we use the privateConversationData property of the session object. We also take the opportunity the compare the state value before and after the authrorization to detect CSRF scenarios:

Step 3: Test your application locally

Install the Bot Framework Emulator

Before deploying the bot to Azure, we need to test it locally. To do this, download the Bot Framework Emulator. It is a standalone application to test bots locally and remotely.

Configure ngrok to test the OAuth2 callbacks

Because we use an Azure AD Application in the cloud, we have to find a way to redirect authorization callbacks to our localhost environement. To do this, we use ngrok, wich a tunneling tool that fits perfectly for this usage. You can get it by downloading it directly on the website or using npm (npm i ngrok -g).

Start the ngrok console and create a new redirection by typing the following command:

Copy the generated URL and use it as the REPLY URL of the Azure AD Application:

In the solution, open the launch.json file and replace the value of the REDIRECT_URI parameter:
Important note: because URLs are generated randomly by ngrok, you have to reconfigure the new URL manually (AAD App + launch.json) every time you shutdown the ngrok console. To get the same URL every time, you must have a paid plan from the ngrok website.

 Start your Node.js application from Visual Studio Code:

Finally, open the Bot Framework Emulator and connect to your local bot using the http://localhost:3978 URL (without client id and secret). You should be able to talk with the bot now and authenticate with Azure AD:


Reset the bot state

For debugging purpose, I’ve added a “reset” command just to reset the bot state and ask for a new authentication:

In the previous versions of the Bot Framework it seems that the /deleteprofile could be used but it didn’t work for me.

Step 4: Deploy your bot and test it with multiple channels

Deploy the Node js application to Azure

In Azure, create a new Node.js empty web application. You can either fork the whole code from my own repository or download the ZIP directly:

Then, you have several ways to deploy your application, the choice is up to you (FTP, Local Git, TFS, etc.).

Register the bot

Go the the following URL, sign-in and register a new bot. For the endpoint URL, put the URL of the Azure web application. Don’t forget the httpand the /api/messages route:

Generate the Microsoft App ID and password. Save the password, you will need it just after!

Set Azure web application settings 

In the Azure web application settings enter the Microsoft App ID and password from the preivous step and set the redirect URL according to your environnement :

  • MICROSOFT_APP_ID: the application Id of your bot.
  • MICROSOFT_APP_PASSWORD: the application password of your bot.
  • REDIRECT_URI: the redirect URL for the Azure AD application. Here, the Azure web application itself (https://<your host name>

Update the reply URL of the Azure AD App and test your bot!

Before playing with your bot, update the REPLY URL in the Azure AD App to point to your Azure web application callback URL:

Go back to the bot framework portal and test your bot. You should be able to talk with it and connect from the web chat control. Try to search for some content in your SharePoint portal (KQL syntax):

Here are the results for Skype and Teams channels. You can see the different visuals of the sign-in card of the Bot Framework depending the channel (except for Teams).

Final thoughts

SharePoint and bots, why would we want to do this?

Even though this example works with any OAuth2 protected APIs (like Graph and so on), the interaction between SharePoint and bots is something especially interesting. Think about it: what is the first thing that users complain about their portal? They can’t find anything, right? To understand this issue, let’s take a look at their possibilities to access content in SharePoint/Office 365:

Strucural navigation with links (static pages, news, sites, etc.)

Too many links can be overwhelming and degrade the user experience. You can not put all your information into the menus so that’s why you need to complete with the search engine in most cases.

The classic SharePoint search engine

Like each of us when using tools like Google Bing, users don’t use the search syntax (KQL) and available operators like OR, AND, etc. and even worse, they don’t know what property names to use to build complex queries. That’s why they expect a lot of the free text search capability. In most cases, searches are done in two steps: a free text search and then refiners to narrow the results. It is the classic pattern even with fine tuned search settings. It can be quite optimal but requires a serious configuration to obtain good results.

Delve and the Office Graph

An other way to search for content is Delve. It can be seen as a search engine but focused to the current user. Thanks to the Office Graph, Delve is “smarter” than the classic SharePoint search engine for free text searches, but the results are only related to the current user and there are no refiners (not very suitable for enterprise content search) . Behind the scenes the SharePoint index is used to get results.

And that’s it. Apart navigation menus, every time, free text queries are used to search for content and it is up to the underlying engine to understand the intent of the user and show the more relevant results (or the more relevant refiners so users can narrow the results). So, what do we have to enhance the content discovery?

Intents recognition is the key

In my opinion, bots are the next evolution of the traditional search tools. They represent an other alternative to discover content and information across portals (especially SharePoint portals, where all the business content belongs to) but not only. They can be used with multiple common channels in the enterprise (Skype, Teams, Slack, etc.) and, like mentionned by Stéphane Eyskens in his article (very interesting blog blog btw), coupled with service like LUIS (Language Understanding Intelligent Service), bots can become a powerful feature for your users to enhance the SharePoint search engine by performing the relevant queries using natural language and intents detection.

You may think: and SharePoint query rules?

Yes, query rules can be seen as a basic intent detection system and can help you to build the complex queries automatically depending of the input. However, they will never be as accurate as LUIS in terms of intent recognition. Moreover, they can only target the SharePoint search engine (so no graph queries or other systems). LUIS is independent of any underlying implementation, it is up to your bot logic to “plug” the right intents to the right queries (it can be SharePoint or something else). Intent recognition is the key to perform accurate search and LUIS is particularly brilliant at this. Bots can be seen as the “intelligent search box” in front of it.

And you, what do you think about bots in the context of an enterprise portal?


Add yours
  1. Mark

    Frank! This is great stuff. Thanks for putting this together. I agree with you that bots just might be the future of a lot of things in the enterprise especially search. We are in the process of building a new virtual assistant bot called “Evan” that helps companies get the most out of their office 365 and SharePoint investment.

    • Franck Cornu

      Thanks Mark! Good to know that there are some companies investing in these technologies! It would be very cool if you could share your experience with the community. It can be a great use case example for bots.

  2. Sarav

    Hi Frank, Getting “The page you are looking for cannot be displayed because an invalid method (HTTP verb) is being used” when hitting Azure node.js site, any ideas please?

    • Franck Cornu

      Hi Tiger, the launch.json file is very specific to VSCode and is automatically generated when you create a new debug configuration within the tool. Just add your values in the env property like this.

      “env”:{ “REDIRECT_URI”: “” }

+ Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.