Monday 14 May 2018

SPFx: Calling Microsoft Graph API from an AAD secured Azure Function on behalf of a user

This post is part of a series where we explore consuming Azure AD secured Azure Functions from SharePoint Framework components. Articles in the series:

1) SharePoint Framework: Calling AAD secured Azure Function on behalf of a user
2) Calling Microsoft Graph API from an AAD secured Azure Function on behalf of a user (this post)
3) SharePoint Framework: Calling back to SharePoint from an AAD secured Azure Function on behalf of a user

In the previous post, we were successfully able to call an AAD secured Azure Function from a SharePoint Framework web part.

Now once we are in the Function, lets see how to make a call to the Microsoft Graph on behalf of the logged in user. We will only focus on the Azure Function here, to fully understand the set up and auth process, I recommend you check out the previous post.

Updates to the Azure AD app registration:

In order to call the Microsoft Graph, we will need to add a Client Secret to the Azure AD app registration.

We don't need to add any new permission scopes for the purposes of this post as we are going to make a call to the /v1.0/me endpoint which requires the User.Read permission. According to the SPFx docs, if we exchange the SPFx generated token for a MS Graph token, it will automatically have the User.Read.All permission scope.

If you want to do anything beyond this with the Microsoft Graph, you will need to add the relevant permissions scope and grant permissions to it. In the next post, we will see how to do this by granting permissions to the "Office 365 SharePoint Online" permissions scope.

Here is what we are going to do in this post:

When the Azure Function executes, we already have an access token sent by the SharePoint Framework AadHttpClient in the Authorization header. This access token has the "user_impersonation" scope which only allows it to access the Azure Function. It cannot be directly used to call the Microsoft Graph.

In order to obtain new access token that will work with the Microsoft Graph, we will have to request it using the existing access token. Once we have the new token, we are able to make a call to the Microsoft Graph:

Once this function is called from our SharePoint Framework web part, we are able to get data back from the graph:

Thanks for reading!


Unknown said...

hi Vardhaman

glad to have found this blog and going through various posts to find something similar that we are trying.

our requirement is to

dynamics 365 <-> custom .net api <-> sharepoint online

and this should happen without the user having to provide credentials or pass their credentials during the process. we can do this using client credentials but then that ends up using a service account and we lose user context.

i am looking at the adal authenticationcontext.acquiretokenasync method but not sure which overloaded method to use as each one of them needs either user credentials or client credentials.

what would you recommend?

Rajesh Shirpuram said...

Hi Vardhaman,

do we have to use Azure function in order to use application permission? In our case, we are trying to develop a spfx web part which will display a out of office dates from users outlook calendar in SharePoint team sites. The traditional team calendar won't work for us, since a user can be part of mulitple teams and updating teams calendar across all sites is cumbersome.

We understand, our application needs Calendar.Read permissions to read all user calendars from our tenant. I've double checked all settings and made sure permissions are set in the Azure AD App as well but for some reason I'm always getting 403 Access Denied.

Any direction would be much appreciated. Thanks!

russell said...

Hi Vardhaman,
Thakns for posting this. I git a question though. This sample works great when I run in in Azure, but when I debug locally it fails at the line
var userImpersonationAccessToken = req.Headers.Authorization.Parameter;

The req.Headers.Authorization is null when running it through the VS2017 Debugger. Any Ideas how to get around this?

Thanks Again
Russell Gove

russell said...

Thanks for posting, this really helped me.
O got a question, in my two tenants the line
string tenantId = ClaimsPrincipal.Current.FindFirst("")?.Value;

is there somethingh i need to do in the registration to have it pass the tenantID?