Using Microsoft Graph as a Microsoft Copilot for Security Plugin with Delegated Access
Microsoft Graph offers a powerful and flexible way to retrieve data from several Microsoft products. Using well documented REST APIs you can pull data from diverse sources like security incidents, SharePoint documents, emails, Teams chat among several others. All Graph API calls support the OData specification and return data in JSON format. OData URL specification allow REST calls to include select, filter and other clauses all of which give control to the amount of data we want the API response to include.
Microsoft Copilot for Security (Copilot) is a large language model (LLM) based generative Artificial Intelligence (AI) system for cybersecurity use cases. Copilot is not a monolithic system but is an ecosystem running on a platform that allows data requests from multiple sources using a unique plugin mechanism. The plugin mechanism gives Copilot the capability to pull data for any external data source as long as it supports REST API, thus allowing Copilot to make Graph APIs calls.
This article assumes familiarity with Microsoft Graph, Copilot and usage of REST APIs, and is intended as a generic example on calling Graph APIs from Copilot.
Microsoft Graph
Microsoft’s Graph offers a single endpoint (https://graph.microsoft.com), to provide access to rich, data and insights from several sources the Microsoft cloud, including Microsoft 365, Windows, and Enterprise Mobility + Security. If you have not worked with Microsoft Graph API before, the best place to start is its main document page available here.
Like with any other REST API, it is good to use a REST API client (Boomerang, Postman etc.) to experiment and test the API. With Microsoft Graph there is another option called Graph Explorer to evaluate all the APIs. Using Graph Explorer is much faster and convenient than using other REST clients as it handles getting authentication tokens and is also directly linked with the Graph documentation. When you go to Graph Explorer from this link, the main page comes up as shown below:
Once in Graph Explorer, you will be asked to authenticate with your Microsoft tenant credentials. While this is not required to make API calls, it is strongly recommended as after authentication Graph Explorer will retrieve the JAVA Web Token (JWT) for your account which is required as a Bearer token in the header in each Graph API call. JWT will also allow Graph Explorer to retrieve data from your tenant (as compared to generic data shown when not authenticated).
Permissions
Each Graph API call requires that your account (and the JWT) have the required permissions to see the data, more details on Graph permissions are given here. Since Graph Explorer is acting on behalf of the authenticated user, this is termed ‘on behalf of’ authentication with delegated access. The delegated permissions are also called scopes and are contained within the JWT. If you do not have the required permissions, the REST call will return with an ‘Unauthorized’ (HTTP 401) error. For each Graph call, under the ‘Modify permissions’ tab Graph Explorer shows one or more of the permissions needed by the call as shown below:
Depending on your role and permissions assignment in Entra, you can consent to one of the permissions required to make the call. The JWT scope should contain the permissions that allow Graph Explorer or any other application acting on behalf of the user, to successfully retrieve the data required from the call. You can see the content of a JWT and the scope it contains from the jwt.ms website.
Let us define a use case based on which we will decide the Graph APIs to call and then build a Copilot API plugin for it. Before building a Copilot plugin that uses Graph API, make sure you have looked at all the skills present in the several Microsoft () plugins available out-of-the-box in Copilot. New Microsoft plugins and additional skills to existing plugins are constantly being added and this will ensure you are not building a plugin for a functionality that already exists. For our use case we will build a plugin to extract all Alert IDs from an incident and then based on the Alert ID it will allow us to pull the evidence associated with that alert.
Head to Graph Explorer console, authenticate and go to the Security group in the left navigation bar. Selecting the ‘alerts’ option will update the URL in the right pane. If the URL does not point to the new unified Microsoft 365 Alerts and Incident API (ends in ‘alert’ and not ‘alert_v2’), change the URL to end in ‘alert_v2’.
Since it is based on the OData specification, Graph API supports several selection criterion and filter options that narrow the scope of the data being returned. For a Copilot for Security plugin this is very important as use of selection and filters criterion reduces the size of the data being returned by the API allowing Copilot to process it more efficiently. These options are passed as query parameters in the URL and detailed description of supported options are available in the Microsoft Graph documentation here. Note that if the data field your need is not available in the JSON returned from the Graph API call, then it is an advanced use case not covered by this article. In these cases, you will have to modify/massage the data using Logic Apps, Azure Functions or Webservice and then integrate with Copilot.
In our first API call, we will use the $count option that will insert a count field in the output JSON. The $count option is added as query parameter as shown in the screen capture below. Once you press the ‘Run Query’ button Graph Explorer will make the REST API call, the output/response JSON of which is shown in the ‘Response preview’ pane. Note the field ‘@data.count’ that is added by the $count query parameter which shows the number of returned alerts:
Our use case calls for looking at alerts only in a specific incident. Though the returned JSON has a field ‘incidentId’ showing the Incident ID each alert belongs to, there are too many alerts that are not useful. Our goal is to return as minimum data to Copilot as possible, so we will use a Odata filter to narrow down the incident and get alerts assigned to it.
A filter is added using the $filter query parameter and its value is set to ‘incidentId eq ’15’’ that tells Microsoft Graph to only return alerts whose ‘incidentId’ is 15. The output of this call is shown below:
We can see that after adding the filter only 2 alerts are returned. After cross refencing incident 15 in the unified Defender console, the returned information is correct:
Though we have the required alerts, we are still pulling in data fields that are not useful for our use case (we only need alert ids along with their description). To narrow down the fields, we will use the $select query parameter and set its value to ‘id,title’ making the combined URL: https://graph.microsoft.com/v1.0/security/alerts_v2?$filter=incidentID eq ’15’&$count=true&$select=id,title
Making this API request, gives us the exact date we need as show in the ‘Response preview’:
Copilot API Plugin
We are now ready to define the YAML files required to have Copilot make the Graph API call. The main YAML file is given below, for more details on these YAML files and their field refer to this article:
Descriptor:
Name: Defender Specific Alert Details Plugin
DisplayName: Defender Specific Alert Details Plugin
Description: The skills in this plugin will help get Defender alert details via Graph API Call
DescriptionForModel: The skills in this plugin will help get specific defender alert details based on provided incident or alert id.
SupportedAuthTypes:
– AADDelegated
Authorization:
Type: AADDelegated
EntraScopes: https://graph.microsoft.com/.default
SkillGroups:
– Format: API
Settings:
OpenApiSpecUrl: http://<URL for OpenAPI File>/API_Plugin_GraphAPI_Alerts_OAI.yaml
Authentication
Note the value for ‘SupportedAuthTypes’ and ‘Authorization’ defined as ‘AADDelegated’ (Azure Active Directory Delegated). When Authorization is set to ‘AADDelegated’ you tell Copilot to use delegated access (or ‘act on behalf’) of the user who is logged into Copilot, when making the Graph API call. This way Copilot makes it very easy to make Graph API calls, and does not require you having to go to the Microsoft Entra Admin Center and register your application as described here. . For that, we have to use OAuth2 and get an application ID by registering an application and this will be discussed in a follow-on article. Along with ‘AADDelegated’ Copilot supports OAuth2 authentication along with several other listed here:
With the important discussion on authentication out of our way, let us see the second YAML file which is for the OpenAPI specification for our Plugin:
openapi: 3.0.0
info:
title: Defender Specific Alert Details Plugin
description: Skills for getting alert details via Graph API Call
version: “v1”
servers:
– url: https://graph.microsoft.com/v1.0/security
paths:
/alerts_v2?$select=id,title:
get:
operationId: GetAlertIdsFromIncidentId
description: List all alert id’s based on a user provided incident id
ExamplePrompt:
– ‘show me alert ids for the specified incident id’
– ‘Get me all alert ids where incident id is provided’
parameters:
– in: query
name: $filter
schema:
type: string
required: true
description: A filter in the format of “incidentid eq id” where ID is an incident ID provided by the user.
responses:
“200”:
description: OK
content:
application/json:
After placing the OpenAPI definition YAML in an Internet accessible URL, we go to the Copilot console and follow the steps to import the custom plugin:
Once the plugin is imported it will show under the custom plugin area, make sure it has been enabled.
We will now invoke our newly imported plugin’s skill directly to verify that it is able to make a successful call and fetch the data. To invoke a skill directly, click on the prompt icon as shown below:
Select, the ‘See all system capabilities’ link and then search for Alert:
This will show the operationId and Description of the skill. Our plugin has only one skill so far (GetAlertIdsFromIncidentId) so we will select it:
and pass it the value of the filter:
If the call is successful, Copilot will complete all the 3 steps and show the response:
After verification with the earlier call in Graph Explorer the Alerts ids and their descriptions look correct and belong to Incident 15.
You can also invoke a skill directly from the Copilot command window using the ‘/’ command as shown below. This gives the same result as before, confirming that Copilot can successfully make the Graph API call, pass the correct credentials for Delegated access and fetch the data.
Note that if you get a permission denied error, check with your Azure admin if you have the requires roles/permissions to read security related information.
Getting Evidence based on Alert Ids
Now that we have the alerts ids, let us now expand our plugin’s capability to get evidence details about a specific alert. The following Graph API URL: https://graph.microsoft.com/v1.0/security/alerts_v2/{alertid}
will fetch information specific to the ‘alertid’ passed to it. In Graph Explorer, the ‘Response preview’ of this API for alert id ‘fab098dd19-bcbd-61e1-7eb2-08dc96ce5a71’ (part of Incident 15) is shown below:
The call returns a lot of data attributes but as per our use case we are only interested in evidence related data. To only have data related to the evidence information,
https://graph.microsoft.com/v1.0/security/alerts_v2/{alertid}?$select=evidence
The Response preview for the updated URL call is shown below:
Now we need to have this capability added to our plugin. The main YAML file will remain the same but the OpenAPI specification will change to support one more REST API. The updated YAML file is given below:
openapi: 3.0.0
info:
title: Defender Specific Alert Details Plugin
description: Skills for getting alert details via Graph API Call
version: “v1”
servers:
– url: https://graph.microsoft.com/v1.0/security
paths:
/alerts_v2?$select=id,title:
get:
operationId: GetAlertIdsFromIncidentId
description: List all alert id’s based on a user provided incident id
ExamplePrompt:
– ‘show me alert ids for the specified incident id’
– ‘Get me all alert ids where incident id is provided’
parameters:
– in: query
name: $filter
schema:
type: string
required: true
description: A filter in the format of “incidentid eq id” where ID is an incident ID provided by the user.
responses:
“200”:
description: OK
content:
application/json:
# New API added
/alerts_v2/{alertid}?$select=evidence:
get:
operationId: GetEvidenceForSpecificAlert
description: Get all the evidence details of a specific alert id
parameters:
– in: path
name: alertid
schema:
type: string
required: true
description: id of the alert
responses:
“200”:
description: OK
content:
application/json:
Note that that $select query parameter is hard-coded but the alert before it is taken a path input. OpenAPI specifications allow fixed query parameters after variable fields which is nice and helps us here.
After re-importing (delete old plugin and import again) the updated plugin, let us invoke the skill directly as we have done before with the same alert id. First search by the Alert, and now we will see two skills for our plugin:
Select ‘GetEvidenceForSpecificAlert’ and enter the alert id:
Copilot makes a successful call and neatly summaries each of the evidence items:
The evidence API call pulls in several evidence objects, and if you need to see data only in a specific evidence, Copilot will need to be prompted to do the filtering once the data is received from the API call. The following prompt will show details of only the Analyzed Message Evidence:
“Get evidence for specific alert with id fab098dd19-bcbd-61e1-7eb2-08dc96ce5a71 and show the details contained in the Analyzed Message Evidence”:
In this article, we have shown how straightforward it is to build a Copilot for Security plugin that makes Graph API calls. We used Copilot’s ‘AADDelegated’ authentication type which allows us to make Graph API calls with delegated access. In a follow up article, we will look at making Graph API calls from Copilot with OAuth2 authentication.
Microsoft Tech Community – Latest Blogs –Read More