Monday, February 19, 2018

Minimal path to awesomeness when moving Microsoft Graph calls to SharePoint Framework v1.4.1


Image by Jeremy Bishop at Unsplash

Phew.. that title was a mouthful. When SPFx v1.4.1 was released the other day, the GraphHttpClient object in SPFx was deprecated in favor of either the AadHttpClient object or the MSGraphClient object. If all you care about is Microsoft Graph calls, then they do pretty much the same, except the MSGraphClient object allows a fluent API to build up your queries with selects, sorts and filters, whereas the AadHttpClient takes a handcrafted URL.

So, from a minimal path perspective the AadHttpClient makes more sense as it takes complete URL’s, and we don’t have to break up the call into a fluid syntax. Also, the MSGraphClient is currently in preview.

Note: If your tenant is not on Targeted Release (TR), you will not be able to grant the needed graph scopes using the SharePoint Admin UI or with SPO Management PowerShell. Uploading the app package will also not work on a normal tenant so be patient.

Below is a code snippet which lists all groups in your tenant using the old graph client.

import { GraphHttpClient, GraphHttpClientResponse } from '@microsoft/sp-http';

// List all groups
let graphClient = this.context.graphHttpClient;
let response: GraphHttpClientResponse = await graphClient.get('v1.0/groups', GraphHttpClient.configurations.v1);
// Check that the request was successful
if (response.ok) {
    return await response.json();
}
else {
    // Reject with the error message
    let error = new Error(response.statusText);
    throw error;
}

And here is the same code using AadHttpClient.

import { AadHttpClient, HttpClientResponse } from "@microsoft/sp-http";

const aadClient: AadHttpClient = new AadHttpClient(
    this.context.serviceScope, "https://graph.microsoft.com"
);

let response: HttpClientResponse = await aadClient.get("https://graph.microsoft.com/v1.0/groups", AadHttpClient.configurations.v1);
// Check that the request was successful
if (response.ok) {
    return await response.json();
}
else {
    // Reject with the error message
    let error = new Error(response.statusText);
    throw error;
}

The main difference being that there is no existing instance on the context object for the AadHttpClient, and you pass in the full URL to the Graph instead of just the path.

Once you have re-written the code there is one last piece to the puzzle. By default SPFx have no graph access what so ever, which means you need to specify which scopes you need access to and grant access to them.

In package-solution.json you have to add a new section describing what Microsoft Graph permissions you need access to. If you read my post on the old graph client you know that it “magically” included scopes for Groups and Reports. To mimic the groups scope add a section as outlined below. And make sure the resource name is “Microsoft Graph”.

{
    "$schema": "https://dev.office.com/json-schemas/spfx-build/package-solution.schema.json",
    "solution": {
        "name": "Some solution",
        "id": "<id>",
        "version": "1.0.0.0",
        "includeClientSideAssets": true,
        "skipFeatureDeployment": false,
        "webApiPermissionRequests": [
            {
                "resource": "Microsoft Graph",
                "scope": "Group.ReadWrite.All"
            }
        ]
    },
    "paths": {
        "zippedPackage": "solution/pzl-some-solution.sppkg"
    }
}

Make sure you enter the scope exactly as listed in the documentation as there is no validation on this. And add one resource/scope section per scope – even if they are on the same resource.

If this is your first SharePoint Framework solution granting a particular scope, you need to deploy the .sppkg file at least once before you can test your part/extension using the workbench. This is because a tenant admin have to approve the scopes you need at this particular tenant.

The below screenshot is from my enable Teams extension, where it prompts you to approve of the scopes from the Service Principal Permissions Management Page.

image

The management page for approval is available from the new SharePoint Admin center, which is in preview from TR clients. Below you can see the scope for Microsoft Graph has been extracted from my app package. Once I approve this scope as a tenant admin, then any SPFx solution may use this scope from now on, without an explicit approval.

image

Also, if you later revoke access to a resource and scope, this will impact all SPFx solutions relying on this scope. To sum it up: resource scope grants are tenant scoped, not SPFx solution scoped. You can read more about this at https://docs.microsoft.com/en-us/sharepoint/dev/spfx/use-aadhttpclient.

If everything went according to plan, you have now moved off the deprecated graph api, and you are using the new one. If you would rather use MSGraphClient, check out the tutorial at https://docs.microsoft.com/en-us/sharepoint/dev/spfx/use-aad-tutorial.

Summary

In order to move your Microsoft Graph calls over to the new API released with SPFx v1.4.1 you need to explicitly list the permission scopes needed in package-solution.json, as well as have a tenant admin grant access to those scopes once the sppkg have been uploaded in your tenant.

It might seem like more work for the developer, and it is in a way, but organizations will have more control and more flexibility of what Microsoft Graph API’s a SPFx solution can call. Which equals more freedom and more control. Good for devs, good for IT admins!