Wednesday 2 January 2019

Working with Application Permissions (App-Only Auth) in SharePoint Online and the Microsoft Graph

When working with SharePoint Online or the Microsoft Graph, there are many scenarios in which we need to read or write data without a user context. It might be a scheduled process, or it might be an operation that requires elevated permissions. In such scenarios, it is quite common for the solution to use "Application permissions" (a.k.a App-Only Authentication). This lets the solution have its own identity which can be used to grant the required permissions.

When working with Application permissions in Office 365, there are a lot of moving pieces to deal with like Client Ids, Client Secrets, Azure AD App Registrations, Certificates, Add-In Registrations, AppRegNew.aspx, AppInv.aspx etc.

What I want to do in this post is to explore different options for configuring and granting application permissions. There are a few combinations possible with the different moving pieces. My aim in this post is to explore them and determine which combination might be suitable for certain scenarios. We will also see some sample code which demonstrates how to authenticate with SPO and the Microsoft Graph using the different authentication options.

Here is a table I have put together which summarises the different options for working with applications permissions in SPO and the Microsoft Graph API. We will go through each on them in detail.



1) Interact with data from SharePoint Online with an Azure AD App Registration


If your solution uses an Azure AD App Registration created from the Azure AD portal and you want to read or write data to SharePoint Online:

You will need to use a Client Id and Certificate. Have a look at this link for details on how to create an AAD App Registration as well as the certificate: https://docs.microsoft.com/en-us/sharepoint/dev/solution-guidance/security-apponly-azuread

If you try to use a Client Id and Client Secret created through AAD portal you will get the following error:

Microsoft.SharePoint.Client.ServerUnauthorizedAccessException: 'Access denied. You do not have permission to perform this action or access this resource.'

You will also get the "Access Denied" error if you try to write to the User Profile service. Reading from the User Profile service will work. If your solution needs write User Profile service access, your only option would be to use an Add-In registration (see the next section). Writing to the SPO Taxonomy Service will not work either through AAD App Registration or Add-In Registration. Read operations will work. See notes at the end of this post.

Here is some sample code to demo how to use a Client Id and Certificate with the AAD App Registration. You will need the SharePointPnPCoreOnline NuGet package:


2) Interact with data from SharePoint Online with a SharePoint Add-In Registration:


If your solution uses a SharePoint Add-In Registration (created through the /_layouts/15/AppRegNew.aspx page) and you want to read/write data to SharePoint Online:

You will need a Client Id and Client Secret created through the /_layouts/15/AppRegNew.aspx page and permissions granted from the /_layouts/15/AppInv.aspx page

See this link for details on how to create as well as assign permissions to the Add-In Registration:
https://docs.microsoft.com/en-us/sharepoint/dev/solution-guidance/security-apponly-azureacs

Here is a sample of how to use the Add-In registration to interact with data from SharePoint. You will need the SharePointPnPCoreOnline NuGet package.



3) Interact with data from the Microsoft Graph with an Azure AD App Registration


If your solution needs to interact with the Microsoft Graph, the only option is to have an Azure AD App Registration. However, within the Azure AD App Registration you can either use a Client Id, Client Secret pair or you can use the Client Id, Certificate pair as well.

1) Using a Client Id and Certificate:


The process to create the AAD App Registration and Certificate is exactly the same as described above in section 1. Only difference would be that instead of selecting SharePoint Online permissions, the App Registration will have to be granted the relevant permission to the Microsoft Graph.

Once that is done, here is the sample code to use the Client Id and Certificate to get data from the Microsoft Graph:



2) Using a Client Id and Client Secret:

The only change in this approach is using a Client Secret (Password) instead of a certificate. See this link to see how to generate a client secret for the AAD App Registration:
https://docs.microsoft.com/en-us/azure/active-directory/develop/howto-create-service-principal-portal#get-application-id-and-authentication-key

Once you have the Client Id and Client Secret, you can use the sample code to get data from the Microsoft Graph:


In conclusion: 


Considering all factors, I would personally go with one of these two options:

If the solution is strictly going to deal with SharePoint Online data and not any other part of Office 365, you might want to consider the SharePoint Add-In Registration approach with a Client Id and Client Secret. That way you don't have to mess around with certificates. But remember that in the future if the same solution is going to read/write data from the Microsoft Graph, you might have to create another App Registration in Azure AD.

Another option would be to use an Azure AD App Registration with a Client Id and a Certificate. This allows us to interact with most of Office 365 data (including SharePoint Online and the Microsoft Graph) without maintaining separate applications. The caveats to this approach being the added complication of generating and managing certificates and also the fact that writing data to SharePoint Online Taxonomy and User Profile will not work (Reading data will be possible)

Notes:

1) Writing to the SPO Taxonomy Service with Application Permissions does not work from either AAD Portal or Add-In Registration. Read operations work. See more details here:
https://docs.microsoft.com/en-us/sharepoint/dev/solution-guidance/security-apponly#what-are-the-limitations-when-using-app-only

2) For the purpose of this post, I have only considered Azure AD v1.0 endpoint as we are only concerned with organisational accounts and not personal accounts.
https://docs.microsoft.com/en-gb/azure/active-directory/develop/azure-ad-endpoint-comparison

3) Technically, Add-In registrations created from the AppRegNew.aspx page are also registered in Azure AD. They are not visible through the AAD portal but you can list them via PowerShell.

4) It is also possible to create an App Registration in Azure AD and then use the AppInv.aspx page in SharePoint Online to assign it SharePoint specific permissions. You can also use this approach to assign a client secret which never expires to the Add-In registration. For more details on this, you can see this post by the very talented Sergei Sergeev https://spblog.net/post/2018/08/24/SharePoint-lifehacks-create-SharePoint-app-registration-with-client-secret-which-never-expires

It would be great if we can get some confirmation from Microsoft about this approach being supported/recommended. But even then, we will have to manage the SharePoint permissions in a different location than the Microsoft Graph permissions.

Hope you've found the post helpful!

9 comments:

Pradeep Khot said...

Hi Vardhaman,

Really helpful blog. Does the same apply while working in SPFx?

Thanks & Regards
Pradeep Khot

gg said...

How about User Delegated Permission for Microsoft Graph API to create MS Teams?

Alexandre said...

Thanks for your explanations, exactly the post I was looking for. However after having read it, I still have a question about App-Only Auth, quite specific as it concerns Office 365 Video API (which is a SharePoint API under the hood from what I understood) : how does App-Only works with the Office 365 video API.

In order to query the Office Video API, I took the SharePoint Add-In Registration approach. I was able to retrieve a valid token that allowed me to list all the channels on my Office Video SharePoint site (GET {VideoPortalURL}/_api/VideoService/Channels). However when I try to list the videos on an Office Video channel, I receive a 403. Is the Sharepoint Add-In approach not the correct one ?

Swetha said...

Hi Vardhaman,

Have you come across this exception before when getting azure function working with clientid and certificate?

Exception: System.ArgumentNullException: Value cannot be null.
Parameter name: certificate
at Microsoft.IdentityModel.Clients.ActiveDirectory.ClientAssertionCertificate..ctor(String clientId, X509Certificate2 certificate)

Regards,
Swetha

Paulus Limma said...

Hi!

Is there any way to list/debug permissions granted to an Add-In app principal? So the one created with appregnew.aspx. I have used dozens of hours for trying to generate principal with single document library permissions . I can receive access token successfully with Postman, but getting "Access denied. You do not have permission to perform this action or access this resource." error when trying to access documents. Then, after I grant more permissions to principal including the permissions to the parent site, I suddenly sometimes can access the documents. It is super weird that it seems to be impossible to see what permissions app principal have.

Also, I haven't found any way to delete the app principal. Yes, I can press the delete button in appprincipals.aspx, but it is still possible to request an access token for it. I found this interface from Microsoft embarrassingly complex to use.

Any help would be very appreciated!

Paulus Limma

Anonymous said...

No write access to taxonomy! Why M$ why???!!!
I can't describe how disappointed I was to only discover this article AFTER spending 3 days writing an Azure Function to create/update terms in the Managed Metadata Service for my SharePoint Online instance...

Vicky B said...

Hi vardhman,

Thanks for the wonderful information!!!

Can we provision modern team site with group, using the code mentioned in "1) Interact with data from SharePoint Online with an Azure AD App Registration"?

Unknown said...

Trying to understand security implications with App registrations, as I read through the API permissions descriptions i see for example ReadWriteAll - Edit or delete items in all site collections. Does this mean that any external source using this registered app if compromised can delete files from any site?

Vardhaman Deshpande said...

Yes that is possible unless the compromised client secret is revoked. That's why for production scenarios, it's recommended to store the client secrets securely in Azure Key Vault for example.