Blog.

Calling Microsoft Graph API from an Azure Function using JavaScript

Nicolas Bello Camilletti
Nicolas Bello Camilletti
8 min read

Not so long ago, I worked on a project where we take advantage of the Microsoft Graph API to perform some tasks. So far, nothing special as it’s not rocket science nowadays to call a REST API, it is just a simple script to call. To add something more interesting to this scenario, we needed to call this functionality from Microsoft Flow (it would be the same using similar products like IFTTT or Zapier, basically we had a workflow that needs to execute a certain functionality). Based on that, our code needed to be triggered from within the workflow tool and the simplest solution here was to call a web endpoint that executes it (this is one of the most common actions in all the workflow tools).

In addition to that, we knew that the demand of the workflow might change a lot over time. It could be intensely used from time to time (let’s say a random number of 1000 requests in less than a minute as an example) and then it may not be called again for weeks or months. Here is where Azure Functions shows its benefits as it can scale as needed and it only cost you when it’s used while, if we would have chosen to use a web app, we would need to pay for at least one instance every month regardless it was used or not.

The Microsoft Graph API call

So, the first step to work on this was to resolve the scenario locally (without the workflow tool nor Azure). Basically, we need to resolve the functionality itself first and in order to do that, we develop a node.js script that uses request to call the Microsoft Graph API for groups to create a new Security Group (a group without distribution list that is used to controlling user access to in-app resources).

The following code shows how the API is consumed from that script. Note that the token and the name are passed by parameter. Additionally, this function returns a Promise that is successfully resolved when the group is correctly created and rejected when is not.

The createGroup function:

var request = require('request');

function createGroup(token, name) {
  return new Promise((resolve, reject) => {
    const options = {
      method: 'POST',
      url: 'https://graph.microsoft.com/v1.0/groups/',
      headers: {
        'Authorization': 'Bearer ' + token,
        'content-type': 'application/json'
      },
      body: JSON.stringify({
        "displayName": name,
        "mailEnabled": false,
        "securityEnabled": true
      })
    };
    
    request(options, (error, response, body) => {
      const result = JSON.parse(body);
      if (!error && response.statusCode == 204) {
        resolve(result.value);
      } else {
        reject(result);
      }
    });
  });
}

The API Authentication

In order to call Microsoft Graph API, we needed to be authenticated and that is why in the previous section we have a token as a parameter of the function which was used to perform the request. To be able to obtain that token, first we need to register a new Web Application within the Office 365 Azure Active Directory. The following are the steps that you will need to register it.

  1. Sign in to the Azure portal through the Office 365 Admin Portal by selecting the Azure AD admin site.
  2. In the left-hand navigation pane, choose More Services, click App Registrations, and click Add.
  3. Follow the prompts and create a new application.
  4. Select Web App / API as the Application Type.
  5. Provide any redirect URI (e.g. https://GraphAPI) as it’s not relevant for this app.
  6. The application will now show up in the list of applications, click on it to obtain the Application ID (also known as Client ID). Copy it as you’ll need it in the Azure Function code.
  7. In the Settings menu, click on Keys and add a new key (also known as client secret). Also, copy it for use in the Azure Function code.

Once that we have the registered applications along with the client id and secret, we should add the following code to generate the token. Note that we are using the adal npm package to do this easier, calling the acquireTokenWithClientCredentials method of the AuthenticationContext object. Additionally, we have some constants that need to be updated with the client id and secret obtained before as well as the tenant name.

The getToken function:

const adal = require('adal-node');

const TENANT = "{tenant-name-here}.onmicrosoft.com";
const CLIENT_ID = "{Application-id-here}";
const CLIENT_SECRET = "{Application-key-here}";

function getToken() {
  return new Promise((resolve, reject) => {
    const authContext = new adal.AuthenticationContext(`https://login.microsoftonline.com/${TENANT}`);
    authContext.acquireTokenWithClientCredentials(GRAPH_URL, CLIENT_ID, CLIENT_SECRET, (err, tokenRes) => {
      if (err) { reject(err); }
      resolve(tokenRes.accessToken);
    });
  });
}

So, putting all together you will get something like the following.

Putting all together:

const name = 'MyGroup';

getToken().then(token => {
  console.log('Token OK. Next: create the group');
  createGroup(token, name)
    .then(result => {
      console.log('Everything OK.');
      console.log(result);
    }).catch(() => {
      console.log('An error occurred while creating the group');
    });
});

The permissions

If you try to run the code you have until now, you will end up with an error because the group will not be correctly created as the registered app doesn’t have the required permissions.

For each Graph API call you will need a different set of permissions, in this particular case you will need to grant the app created before in the Azure Portal, the Group.ReadWrite.All permission (more information about the Create group endpoint here). The following steps describe how to configure the permissions to your app.

  1. In the Azure Portal’s App Registrations menu, select your application.
  2. In the Settings menu, click on Required permissions.
  3. In the Required permissions menu, click on Microsoft Graph (or add it if it is not listed yet).
  4. In the Enable Access menu, select the Read and write all groups to the organization permissions from Application Permissions and click Save.
  5. Finally, back in the Required permissions menu, click on the Grant Permissions button.

The Azure Function

Now that we have the node.js code ready, we need to update it a bit to use it from an Azure Function. Basically, as we are going to use an HTTP trigger, we need to update the code to receive the name of the new group as parameter in the query string. Also, we might need to return something like the result instead of just showing it in the log. Moreover, we should replace the console object with context for logging and add a call to context.done() to mark that the Function completed running.

The following code shows how it ends up with all the required changes.

The Azure Function code:

// ...

module.exports = function (context, req) {
  context.log('Starting function');
  if (req.query.name) {
    const name = req.query.name;
    context.log('Parameters OK. Next: get token');
    getToken().then(token => {
      context.log('Token OK. Next: create the group');
      createGroup(token, name)
        .then(result => {
          context.log('Everything OK.');
          context.res = {
            status: 200,
            body: JSON.stringify(result),
            headers: {
              'Content-Type': 'application/json'
            }
          };
          context.done();
        }).catch(() => {
          context.log('An error occurred while creating the group');
          context.done();
        });
    });
  } else {
    context.res = {
      status: 400,
      body: "Please pass a name on the query string"
    };
    context.done();        
  }
};

Note that we replaced console with context for logging as specified before and we also added the required calls to done to tell the Function manager that the function completed its execution. Additionally, for retrieving the parameter from the query string we are using the second parameter of the Function, req, which contains the request information including the query parameters data.

Remember that you will need to publish the npm dependencies along with the Azure Functions (more information here).

For more information about working with JS in Azure Functions you can check the Azure Functions JavaScript developer guide.

Final steps

All you have to do now is deploy the Azure Function and hook it up to your Workflow (or just perform the requests to it as needed). You can find this applied to a more complex scenario where external users are invited to the Office 365 tenant and added to groups which are dynamically created here.

I think that this is a great scenario to take as an example of Azure Functions. It can scale without a problem and it will not cost you when the function/workflow is not used. Additionally, it’s easy to call the logic that we need with a simple request, helping us to easily hook it to a lot of different scenarios/things. Moreover, creating the Azure Function using JavaScript give us a lot of flexibility especially because of the incredible number of packages that exist in npm.


More Stories

Migrating my blog once again

5 min read

I already have two post about the migrations of my blog engine to a new stack in the past. I first started writing in my previous work's…

Nicolas Bello Camilletti
Nicolas Bello Camilletti

Understanding Service Workers

5 min read

In the previous post I mentioned service workers several times as a key component for PWAs. Service workers are a crucial component in…

Nicolas Bello Camilletti
Nicolas Bello Camilletti