Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
franz_forsthofer
Employee
Employee
16,087
If you want to access the Microsoft Graph API, an OAuth2 with Authorization Code grant type is required. SAP Cloud Integration supports to fetch access tokens of an OAuth2 Authorization Code credential in a script step of an integration flow. With this new feature, you can call the Microsoft Graph API in an integration flow with the HTTP receiver adapter. Microsoft Graph offers many queries; in this blog we show how you can read and create pages in Microsoft One Note by using an integration flow as an example for calling the Microsoft Graph API from CPI.

This new feature is available from Cloud Integration NEO release 3.33 onwards or from Cloud Integration CLoud Foundry release 6.9 onwards.

Prerequisites


To connect to the Microsoft Graph API, you need an organizational directory/tenant in Microsoft Azure Active Directory and a user in this directory which has sufficient roles assigned to execute the API queries you want to use. In our example, we use queries to Microsoft One Note; therefore, the user must have a subscription to Microsoft One Note (for example "Microsoft 365 Business Basic" license). For the configuration tasks in the Azure Active Directory, you also need an administrator user with the “Application administrator” and the “Application developer” role.

In addition, you need a SAP Cloud Integration tenant on which you have a user with the “Integration Developer” role and a user which can call the integration flow (user with role ESBMessaging.send).

Steps


To set up the OAuth2 connection towards Microsoft Graph with SAP Cloud Integration, execute the following steps:

  • Step 1: Determine Requests and Scopes

  • Step 2: Determine Redirect URI

  • Step 3: Create OAuth Client/App in Microsoft Azure Active Directory

  • Step 4: Create OAuth2 Authorization Code Credential in your SAP Cloud Integration tenant

  • Step 5: Create integration flow with script step and HTTP receiver adapter

  • Step 6. Execute the integration flow


Step 1: Determine Requests and Necessary Scopes


First, you determine which requests you want to execute. You find an overview of the possible requests in the documentation of the Microsoft Graph APIhttps://docs.microsoft.com/en-us/graph/api/overview. Another good source to get an overview is the Microsoft Graph Explorer.

We want to execute three requests, which are related with the One Note application of a user:

  • list One Note sections

  • list pages of a certain One Note section

  • create a new One Note page


We have to find out which scopes/permissions are necessary to execute these requests.

In the graph explorer, you can select the query you want to execute. Then, you can see the permissions (=scopes) you need (see Tab "Modify permissions"). Below, you see two screenshots of the Microsoft Graph Explorer tool which show the request URLs and the permissions for executing the first two requests (list One Note sections, list pages of a certain One Note section):



In the documentation of the Microsoft Graph API, we find the request for the One Note Page Creation:


We can see from this information that all tree requests can be executed with the permission Notes.ReadWrite.All. We now have to add the prefix https://graph.microsoft.com/ to the permission name to get the scope which we need for the creation of the Cloud Integration Credential: https://graph.microsoft.com/Notes.ReadWrite.all 
Permission: Notes.ReadWrite.All -> Scope: https://graph.microsoft.com/Notes.ReadWrite.All

For more information why this prefix has to be added, have a look at https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-permissions-and-consent. There you find the following information: "Each permission is indicated by appending the permission value to the resource's identifier (the Application ID URI)."

Step 2 - 4: Redirect URI - OAuth Client - OAuth2 Authorization Code Credential


Steps 2 - 4  are already outlined in detail in the blog https://blogs.sap.com/2020/08/20/cloud-intgration-connect-to-microsoft-365-mail-with-oauth2/. Please follow the description in that blog for these steps. See chapters

  • Determine Redirect URI

  • Create OAuth Client/App in Microsoft Azure Active Directory

  • Create OAuth2 Authorization Code Credential in your SAP Cloud Integration tenant


For step 4 (Create OAuth2 Authorization Code Credential in your SAP Cloud Integration tenant) you have to use different scopes than specified in that blog; you have to use the scope https://graph.microsoft.com/Notes.ReadWrite.all. (You can also specify several scopes in the "scope" field by separating them with the space character.)

The following screenshot shows the "OAuth2 Authorization Code" creation dialog with the correct scope.



Step 5: Create integration flow with script step and HTTP receiver adapter


We create an integration flow with a script step which uses the created OAuth2 Authorization Code credential and a HTTP receiver adapter which calls the Microsoft Graph API. The following screenshot shows the integration flow we want to build:


In the following sub-chapters, you learn how the steps and adapters of the integration flow are configured.

Sender HTTPS Adapter


The HTTPS sender adapter is configured as follows:



Groovy Script


The groovy script contains the new functionality to fetch an access token from the OAuth2 Authorization Code credential:
import com.sap.gateway.ip.core.customdev.util.Message;
import com.sap.it.api.securestore.SecureStoreService;
import com.sap.it.api.securestore.AccessTokenAndUser;
import com.sap.it.api.securestore.exception.SecureStoreException;
import com.sap.it.api.ITApiFactory;
def Message processData(Message message) {

SecureStoreService secureStoreService = ITApiFactory.getService(SecureStoreService.class, null);

AccessTokenAndUser accessTokenAndUser = secureStoreService.getAccesTokenForOauth2AuthorizationCodeCredential("MICROSOFT_ONE_NOTE_ACCESS");
String token = accessTokenAndUser.getAccessToken();

message.setHeader("Authorization", "Bearer "+token);


return message;
}

By calling the method

getAccesTokenForOauth2AuthorizationCodeCredential("MICROSOFT_ONE_NOTE_ACCESS"),

you fetch the access token of the OAuth2 Authorization Code credential with name "MICROSOFT_ONE_NOTE_ACCESS".

Also the line

message.setHeader("Authorization", "Bearer "+token);

is important. With this line you fill the "Authorization" header with the access token. This header is sent by by the HTTP receiver adapter as HTTP header to the Microsoft Graph endpoint to establish the authentication.

Receiver HTTP Adapter


To be able to make different kind of requests to Microsoft Graph, we parameterize the "Address" and "Method" field in the HTTP receiver adapter as follows:


The address is read from the header with the name "address" and the method is read from the header with the name "method".

Also, we set the "Authentication" to "None" because we've already set the "Authorization" header in the script step.

Remove Headers Content Modifier


We call the HTTP receiver adapter in a request reply step because we want to clean-up headers after the call to Microsoft Graph. Therefore, we add the "Remove Headers" Content Modifier step after the "Request-Reply" step. Most importantly, we remove the "Authorization" header which is set by the script step and which contains the token. If we do not remove this header, the token will be part of the response to the sender and the sender could access this security relevant information. We also remove the other two headers "address" and "method" as shown in the following screenshot:



Allow Headers "address", "method", and "Content-Type"


We want to use the headers "address", "method", and "Content-Type" to configure the HTTP Receiver adapter. The values for these headers shall be sent from the sender client. In the "Runtime Configuration" of the integration flow, you specify these headers in the "Allowed Headers" field. To get to the integration flow properties view, click on an empty space in the integration flow modeling area:



Step 6. Execute the integration flow


To be able to call the integration flow endpoint, you need a user with the ESBMessaging.send role assigned. We assume here that you are familiar with setting up the basic authentication in your http client (for example Postman); we do not explain the authentication part of the http client.

After you've deployed the integration flow, you find the integration flow endpoint in the Operations View in the "Manage Integration Content" tile:


You need this endpoint URL in the following client configurations.

List One Note Sections


In the first chapter, we've already found out that we have to execute the following call towards Microsoft Graph to list the one note sections.
GET https://graph.microsoft.com/v1.0/me/onenote/sections

Therefore, we call the integration flow endpoint with the "method" header value "GET" and the "address" header value "https://graph.microsoft.com/v1.0/me/onenote/sections". In the following block, you see the configuration details you have to enter in your http client:
GET https://<host from the iflow endpoint>/http/call_microsoft_graph_api

Headers:
Content-Type: text/plain
address: https://graph.microsoft.com/v1.0/me/onenote/sections
method: GET

After you've executed the call, you will get a response body similar to the following (if you have at least one section in One Note):
{
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#users('a92e5487-af32-4283-93eb-dd47253c7856')/onenote/sections",
"value": [
{
"id": "1-ab9ffe21-abc1-56a9-1721-3b39f07a8f36",
"self": "https://graph.microsoft.com/v1.0/users/a92e5487-af32-4283-93eb-dd47253c7856/onenote/sections/1-ab9ffe21-abc1-56a9-1721-3b39f07a8f36",
"createdDateTime": "2020-11-19T14:16:31Z",
"displayName": "Test Section",
"lastModifiedDateTime": "2020-11-20T15:01:45Z",
"isDefault": false,
"pagesUrl": "https://graph.microsoft.com/v1.0/users/a92e5487-af32-4283-93eb-dd47253c7856/onenote/sections/1-ab9ffe21-abc1-56a9-1721-3b39f07a8f36/pages",
"createdBy": {
"user": {
"id": "a92e5487-af32-4283-93eb-dd47253c7856",
"displayName": "Test User"
}
},
"lastModifiedBy": {
"user": {
"id": "a92e5487-af32-4283-93eb-dd47253c7856",
"displayName": "Test User"
}
},
"links": {
"oneNoteClientUrl": {
"href": "onenote:https://aintpomail-my.sharepoint.com/personal/test_user_test_com/Documents/Notebooks/My%20Notebook%20@%20Work/Research%20notes.one"
},
"oneNoteWebUrl": {
"href": "https://aintpomail-my.sharepoint.com/personal/test_user_test_com/Documents/Notebooks/My%20Notebook%20@%20Work?wd=target%28%2F%2FResearch%20notes.one%7C%2F%29"
}
},
"parentNotebook@odata.context": "https://graph.microsoft.com/v1.0/$metadata#users('a92e5487-af32-4283-93eb-dd47253c7856')/onenote/sections('1-ab9ffe21-abc1-56a9-1721-3b39f07a8f36')/parentNotebook/$entity",
"parentNotebook": {
"id": "1-72f96a39-135f-43a7-b907-3c29b90e6c63",
"displayName": "My Notebook @ Work",
"self": "https://graph.microsoft.com/v1.0/users/a92e5487-af32-4283-93eb-dd47253c7856/onenote/notebooks/1-72f96a39-135f-43a7-b907-3c29b90e6c63"
},
"parentSectionGroup@odata.context": "https://graph.microsoft.com/v1.0/$metadata#users('a92e5487-af32-4283-93eb-dd47253c7856')/onenote/sections('1-ab9ffe21-abc1-56a9-1721-3b39f07a8f36')/parentSectionGroup/$entity",
"parentSectionGroup": null
}
]
}

Remember the section ID "1-ab9ffe21-abc1-56a9-1721-3b39f07a8f36"; we need it for the next call.

Create One Note Page


To create a one Note Page in the section "1-ab9ffe21-abc1-56a9-1721-3b39f07a8f36", we have to make the following request to Microsoft Graph (here we use an example body, but you can adapt this body to your needs; for more information see the documentation of the Microsoft Graph API😞
POST https://graph.microsoft.com/v1.0/me/onenote/sections/1-ab9ffe21-abc1-56a9-1721-3b39f07a8f36/pages

Headers:
Content-Type: multipart/form-data; boundary=MyPartBoundary198374

Body:
--MyPartBoundary198374
Content-Disposition:form-data; name="Presentation"
Content-Type:text/html

<!DOCTYPE html>
<html>
<head>
<title>Note Page Demo</title>
<meta name="created" content="2020-11-21T09:00:00-08:00" />
</head>
<body>
<p>Test creating Note Page via API</p>
</html>

--MyPartBoundary198374--

Hence, we use the following request towards the integration flow endpoint:
POST https://<host from the iflow endpoint>/http/call_microsoft_graph_api

Headers:
Content-Type: multipart/form-data; boundary=MyPartBoundary198374
address: https://graph.microsoft.com/v1.0/me/onenote/sections/1-ab9ffe21-abc1-56a9-1721-3b39f07a8f36/pages
method: POST

Body:
--MyPartBoundary198374
Content-Disposition:form-data; name="Presentation"
Content-Type:text/html

<!DOCTYPE html>
<html>
<head>
<title>Note Page Demo</title>
<meta name="created" content="2020-11-21T09:00:00-08:00" />
</head>
<body>
<p>Test creating Note Page via API</p>
</html>

--MyPartBoundary198374--

If the creation is successful, you'll get as HTTP return status code 201.

List One Note Pages


Now you can check with the following call to the integration flow endpoint whether the page created can be queried.
GET https://<host from the iflow endpoint>/http/call_microsoft_graph_api

Headers:
Content-Type: text/plain
address: https://graph.microsoft.com/v1.0/me/onenote/sections/1-ab9ffe21-abc1-56a9-1721-3b39f07a8f36/pages
method: GET
5 Comments