# Protect Azure Bot Messaging Endpoint

So far, we have managed to get a simple bot up and running in OutSystems Developer Cloud (ODC). In fact, we've done much more than that. We built a messaging endpoint that can serve as a gateway to multiple bot applications in ODC, where each bot application can respond to inbound messages triggered as events individually. This setup is quite versatile and dynamic.

However, we are still missing two important implementations. First, our messaging endpoint is publicly available without any authorization checks. Essentially, anything could mimic an inbound message, and our bot would react, which is not good.

Second, in some scenarios, we need a user's credentials, not just their ID, to perform actions on behalf of that user in a bot implementation. Currently, through a Teams channel, we get the identifier of a user logged into Teams, but to use Microsoft Graph API operations on behalf of that user, we need the user to explicitly authenticate to retrieve their access token for Graph API operations.

In this tutorial, we will protect our messaging endpoint to ensure that we only handle requests initiated by Azure AI Bot services. In the next tutorial, we will explore how to authenticate a user and retrieve an access token to act on behalf of a user with the Graph API.

# **Demo Application**

This article series includes a demo application called "**ODC with Bots for Teams Demo**," available on **ODC Forge**. Be sure to download the version of the application that matches each article in this series.

For this article, you need to install Version 0.4 from ODC Forge.

* In the ODC Portal, go to **Forge - All Assets**.
    
* Search for "**ODC with Bots for Teams Demo**".
    
* Click on the Asset **(Do not click on Install on the tile!)**.
    
* Switch to the **Version** tab and click on Install next to **Version 0.4**.
    

Version 0.4 depends on other Forge components:

* **OAuthTokenExchange** - An external logic library that helps retrieve access tokens easily.
    
* **Bot Framework Service API** - A connector library for using Bot Connector API endpoints.
    

# Authenticating Requests to the Messaging Endpoint

Any request from a configured channel is routed through the **Azure AI Bot Connector service**, which adds a **signed JSON Web Token** to the Authorization header of each request. The entire authentication and authorization process is well documented here: [Authenticate requests with the Bot Connector API - Bot Service | Microsoft Learn](https://learn.microsoft.com/en-us/azure/bot-service/rest-api/bot-framework-rest-connector-authentication?view=azure-bot-service-4.0&tabs=multitenant#connector-to-bot). It involves the following steps:

* Retrieve the token from the **Authorization** header.
    
* Parse the **token header** to identify which **key** was used to sign the token.
    
* Retrieve the **public key** for the identified key from the Bot Framework **JSON Web Key Set URI**.
    
* Validate the token.
    

In ODC, we manage all of this with a custom **OnAuthentication** handler on the exposed Messaging endpoint.

## OnAuthentication Handler

In the demo application under **Logic - Integrations - REST**, note that our **MessagingEndpoint** REST API authentication setting is now configured with **Custom**, which includes the **OnAuthentication** handler. **OnAuthentication** runs before a request reaches the actual endpoint.

Double-click the **OnAuthentication** handler to review the implementation.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1738673329255/b0d097b7-5335-4163-ab37-f1d0a643ded9.png align="center")

The **OnAuthentication** handler performs several actions, starting with retrieving the value of the Authorization request header using **Request\_GetHeader** from the HTTP module. The value is formatted as `Bearer <encoded JSON web token>`. The JSON web token consists of three parts separated by dots. Each part is a base64 encoded JSON document.

* **Header** - Contains information about the token and how the signature was calculated.
    
* **Payload** - The token's payload with various key-value pairs, also known as claims.
    
* **Signature** - The signature of the payload.
    

## ParseAuthorizationHeader Action

This action performs some **String\_Split** operations. First, it splits by a single space to divide the Authorization header value into the word "Bearer" and the encoded JSON web token.

Next, it splits the encoded JSON web token by a single dot to separate the Header, Payload, and Signature parts.

Note the individual **IF** conditions that raise an exception if the Authorization header is empty or if the split actions do not produce the expected results.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1738676047708/f846b039-254b-4c93-8aad-0086a5ace7aa.png align="center")

## ParseJwtHeader Action

This action converts the encoded Header of the token into a **JwtHeader** structure and returns it. The Header structure includes the Key Identifier of the public key that we need to use to verify the token's signature.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1738676992280/08abf4e0-18ef-47a2-be45-6eb6ea36efcc.png align="center")

## GetJwksKey Action

This action retrieves the public key from the Bot Framework Identity Provider's JSON Web Key Set endpoint. The Bot Framework Identity Provider issues the signed token, and its URL is `https://login.botframework.com`.

* First we retrieve the Discovery document from the Identity Provider that contains the URI of the JSON Web Key Set endpoint using **GetDiscoveryDocument** from the **OAuthTokenExchange** Forge component.
    
* Then we perform a **GET** request to the endpoint that returns the key sets using **Request\_SubmitGetRequest** from the **HTTP** module and deserialize the response into a structure for easy filtering.
    
* We filter the list of retrieved keys to the key identifier retrieved from the token header using a **ListFilter** action.
    
* And finally we **serialize** the single key and return it.
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1738676733434/ab92d002-b4b7-4775-b648-41bae68e0d61.png align="center")

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text"><strong>Important Note</strong>: This action retrieves the key with every request to the messaging endpoint, which adds extra delay. In a production environment, you should consider periodically syncing the keys from the JWKS endpoint and retrieving the individual key from a cache-enabled entity.</div>
</div>

## ValidateToken Action

In **ValidateToken**, we use **JWT\_ReadToken** from the **Security** module to check the signature with the retrieved public key.

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">If the validation fails, <strong>ValidateToken </strong>will raise an exception.</div>
</div>

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1738676948109/03db5506-f491-4c33-bddf-689b2411a47d.png align="center")

If validation succeeds, the request is forwarded to the Messages endpoint for further processing.

# Summary

At the end of this tutorial, we protected our messaging endpoint by validating the access token sent from the Azure AI Bot service. The great thing about this tutorial is that you can use this method whenever you need to validate a signed JSON web token.

Feel free to leave a comment with your questions or feedback.
