Skip to Content
Product Information
Author's profile photo Franz Forsthofer

Cloud Integration – Call Microsoft Graph API with OAuth 2.0 Authorization Code

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

Assigned Tags

      5 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Fatih Pense
      Fatih Pense

      Hello Franz, thanks for the nice example of using the new "access token in script" feature. This was a common scenario. I usually Alt-Tab between OneNote and CPI so it is an extra memorable example for me.

      One question, are these access tokens cached for the time period of validity?

      Regards,
      Fatih

      Author's profile photo Franz Forsthofer
      Franz Forsthofer
      Blog Post Author

      Hello Faith, the access tokens are cached for 50 minutes. If the access token has a life time of less then 50 minutes, and a request came after the life time of the access token but before the access token was removed from the cache, then still a new access token is fetched.

      Regards Franz

      Author's profile photo Fatih Pense
      Fatih Pense

      Thanks for the clarification, Franz!

      Regards,
      Fatih

      Author's profile photo Kajal .
      Kajal .

      Hey Franz Forsthofer,

      Thanks for this amazing article. I am trying to set destination to Microsoft graph API to use the API in SAP CLoud Platform Workflow. I am using OAuthJWTBearer Authentication type. However, It is not able to authorize me. Can you please help me with the same?

       

      Author's profile photo Federico Bellizia
      Federico Bellizia

      Thank you Franz!!!

       

      Same method works with SAP DWH