Wednesday, June 7, 2017

Accessing Microsoft Graph resources from the SharePoint Framework

You can find the complete sample web part at:

With the recent release of the Developer Preview of the SharePoint Framework it’s now possible to start running queries against the Microsoft Graph without the use of ADAL.

The savior in this case is the introduction of the GraphHttpClient class (which at the time of writing this does not have a documentation page).  If you decode the Bearer token used by GraphHttpClient you can see the following permissions being available:

The Groups permission lets you read information about Office 365 Groups, but not everything as stated in the documentation. You can read the basic information about the group as well as Exchange data like calendar events, but I got access denied when trying to list members of a Group.

The report permission lets you read different usage reports from Office 365, for example all activities in  Office 365 Groups. The response of a usage report call is a redirect URL in which you will the report in CSV format. See the Graph documentation for more information.

I guess time will tell what other resources which will be made available through this end-point.


The important part when using GraphHttpClient is that you pass in a relative URL without a starting slash. For example:

  • v1.0/groups/79958190-024b-4c62-ab55-65dc9a066cac/events
  • beta/reports/Office365GroupsActivity(view='Detail',period='D7')

In my sample web part to be used on the team site of an Office 365 Group I retrieve all calendar entries for the current group with the following code and return a concatenated string of all the calendar entry titles.

Note that my response is of type HttpClientResponse and not GraphHttpClientResponse. For some reason it failed to reference this class, but it inherits from HttpClientResponse without adding anything, so it’s all good. Also note that I get the group id for the current group though context.pageContext.legacyPageContext.groupId. I expect group id to perhaps be available directly on the pageContext object in the future.

public componentDidMount(): void {
    // Group ID is not directly available yet, so we get it from the legacy context
    let groupId = this.props.context.pageContext.legacyPageContext.groupId;
    this.props.context.graphHttpClient.get(`v1.0/groups/${groupId}/events`, GraphHttpClient.configurations.v1).then((response: HttpClientResponse) => {
      if (response.ok) {
        return response.json();
      } else {
    }).then((result: any) => {
      let appointments: string = '';
      for (var i = 0; i < result.value.length; i++) {
        var element = result.value[i];
        appointments += element.subject + "|";
      this.setState({ appointments: appointments });

You can find the complete sample web part at:


  1. Hey,
    Is it possible to get more permissions for the graph?
    Specifically the insights endpoints that are replacing the old graph SP search requests?
    They seem to have taken them away without anything decent to replace...the user having to sign in again just for my graph web part to query the insights API is somewhat less than ideal!!!!

  2. Have you tried doing paging with Spfx and Graph API requests ? I see that adding "previous-page=true" in the next link request is not working for me in case I need to move back to the previous page..any pointers ? !

    1. See

    2. This would mean retrieving all the groups and then handling paging in the spfx webpart. I was looking at calling the graph for every "Next" "Previous" click to get only 10/15/"Page count" values. Looks like i'll have to live with getting all the values for now !

    3. You can bake paging into your app, all up to you how you build it and handle the logic for page 2 etc.

    4. yup. Also, the call to fetch MY O365 groups (memberof) data does not retrieve the site URL. It has to be a separate call at the moment. This operation becomes heavy if I retrieve all the group data on the first load. Previous-page paging would have helped here !

    5. You can craft a link to the site without knowing the URL. Saves you a call.

    6. Yup ended up doing the same thing. Crafted the Url in the webpart