Thursday, May 4, 2017

Fix problem with Access denied exception in provider-hosted apps for Sharepoint

In one of our projects we used provider-hosted app which runs on Azure web site and accesses data in Sharepoint Online site (host web). In this host web there is a list with unique permissions and app needed to make changes in the list items there. Users which used the app not always had edit rights on this list and attempts to change list item caused the following exception:

Access denied. You don't have permissions to perform this action or access this resource.

Problem was caused by the app’s code which uses user client context token:

   1: var spContext = SharePointContextProvider.Current.GetSharePointContext(context);
   2: using (var ctx = spContext.CreateUserClientContextForSPHost())
   3: {
   4:     ...
   5: }

With client context app’s code is only allowed to perform actions which are allowed for the current user. I.e. if user doesn’t have permissions to edit list items in the list, app’s code will fail with Access denied exception shown above.

In order to fix the issue we need to run our code under “elevated privileges”, which in case of app development model means that we need to use app only permissions. SharePointContext class has different method for obtaining app-only client context:

   1: var spContext = SharePointContextProvider.Current.GetSharePointContext(context);
   2: using (var ctx = spContext.CreateAppOnlyClientContextForSPHost())
   3: {
   4:     ...
   5: }

But it is only half. Second step is to allow our app to use app-only permissions. Without that changes described above won’t give any effect. In order to allow the app to use app-only permissions we need to add AllowAppOnlyPolicy="true" attribute to AppPermissionRequests tag inside app manifest and re-install the app through App catalog. Also it is possible to update AppPermissionRequests for already installed app without re-installation. In order to do that go to http://example.com/_layouts/15/appinv.aspx page (where instead of http://example.com you should use your Sharepoint Online tenant), specify app id in the textbox, click Lookup button and specify the following permissions xml:

   1: <AppPermissionRequests AllowAppOnlyPolicy="true">
   2:   <AppPermissionRequest Scope="http://sharepoint/content/sitecollection"
   3: Right="FullControl" />
   4: </AppPermissionRequests>

(in this example apps get Full control over whole site collection. You need to use your own permissions there. The important part now is that AppPermissionRequests tag has AllowAppOnlyPolicy="true" attribute). After that click Create button and then Trust it on the opened window.

Note that if you specify AppPermissionRequests with scope starting from site collection like shown above and less (web, list) it is enough to have site collection admin rights for updating the app. But if you change app permissions on the tenant level (Scope=”http://sharepoint/content/tenant”) you should have tenant admin permissions (see permission scopes in the following article: Add-in permissions in SharePoint 2013).

After these steps app should be able to execute code with elevated privileges using app-only permissions.

1 comment: