Introduction

In this blog post I will demonstrate how to successfully change item permissions via the REST API on SharePoint Online.

Whilst the raw task of updating permissions would be a single action with a tool such as Nintex Workflow, this scenario will focus on achieving this with SharePoint Designer.

Initial challenges

There are a number of considerations when planning a workflow of this type such as:

  • How will the workflow authenticate with SharePoint Online?
  • What actions can I use to update the permissions?
  • What permissions will the workflow need in order to perform these activities?

At a high level, the workflow logic is as follows:

  1. Run everything as a SharePoint 2013 workflow and utilise an “App Step” in order to elevate the workflow permissions
  2. Perform an HTTP request against your SharePoint Online site collection
  3. Extract the Request Digest information from the response (this is your “key” to authenticate future requests)
  4. Perform subsequent HTTP requests to
    • Break permission inheritance on the current item
    • Temporarily add the workflow initiator with custom permissions (more on this later)
    • Remove the old item level permissions
    • Add the new item level permissions

While the above may come across as relatively logical in hindsight, I found the specifics of the process relatively challenging as each activity had to be exact and within the context of SharePoint Designer, there was very little forgiveness when some of the configuration was not perfect.

There are plenty of examples out there which show the process when using SharePoint On Premises, but not many which cover everything end-to-end using SharePoint Online.

Workflow authentication

As the workflow will be running as the user who “initiated” it we need to be mindful of the required permissions to perform specific actions.

My scenario is focused on a user contributing an item to a library, editing it once, and then having their edit permissions removed (i.e. the purpose of the workflow).

The challenge is that the user initially only has basic rights to the library and hence won’t have the ability to perform all of the actions that are required to modify the permissions.

SharePoint 2010 workflows provided us with the opportunity to utilise impersonation to effectively elevate the account that was running the workflow.  The challenge with this approach was that the impersonation account was determined by the user who actually published the workflow.

This introduced maintenance burdens (re: who can update the workflow), and perhaps more importantly making sure that the account that published the workflow continued to exist moving forwards.

Moving forwards, SharePoint 2013 workflows (which is what we have running currently on SharePoint Online) have removed the impersonation model in favour of App Step.

Enable app permissions for workflows

Without going into the technical details, an App Step action is introduced which enables us to insert actions that will be run with elevated permissions.

These elevated permissions are defined on the root site as follows:

Navigate to Site Settings -> Site Features and scroll to the bottom of the list.

Activate the Workflows can use app permissions feature.

This will enable the App Step functionality within SharePoint Designer.

Once this feature is activated, we then need to give permissions to either the site or site collection for the associated workflows.

Grant full control permissions for workflows

This is a one-off step that needs to be performed.

Navigate to Site Settings -> Site app permissions (under the Users and Permissions group)

You should see an entry for Workflow under the App Display Name column.  If you don’t, you may need to simply publish a basic SharePoint workflow to your site to trigger this.

Against the Workflow entry, you will see a value for the App Identifier.  This will take the approximate format of:

i:0i.t|ms.sp.ext|<long GUID here>@<another long GUID here>

You need to copy the first GUID after the and before the @ (but don’t include these symbols).

Next, navigate to a hidden page which takes the format of:

http://yourtenant/sites/yoursitecollection/_layouts/15/appinv.aspx

This page simply requires to you paste in the GUID copied above into the App Id field and then click Loopup.

The other fields will then be automatically populated for you.

Within the App’s Permissions Request XML field you will need to paste in the appropriate XML based on the permission level you want to provide.  Note that the XML below simply needs to be pasted “as is” i.e. no need to modify the scope parameter for your environment.

Give workflows access to the overall site collection

<AppPermissionRequests>
  <AppPermissionRequest Scope="http://sharepoint/content/sitecollection" Right="FullControl" />
</AppPermissionRequests>

Give workflows access to subsites only

<AppPermissionRequests>
  <AppPermissionRequest Scope="http://sharepoint/content/sitecollection/web" Right="FullControl" />
</AppPermissionRequests>

Click Create and when prompted,  select Trust It.

Workflow creation

Within SharePoint Designer, navigate to the target library where you would like to run the workflow and create a new workflow.

Once you have created the workflow you can navigate back to the workflow settings and specify that the workflow should fire on item creation and/or modification.  In my case I wanted to trigger on modification.

Workflow logic

I broke my workflow down into a series of stages to assist in the development.  Each stage is elaborated on below:

Initialise authentication
Get group ID
Get target role ID
Break permissions inheritance
Add temporary read permissions for initiator
Remove current role assignment
Add new role assignment
Remove temporary read permissions

To provide the big picture up front, the overall workflow comes together as follows:

Initialise authentication

The purpose of this stage is to create our initial connection to SharePoint Online and extract our digest value for this session.

I will run through each action to provide additional information.

1. Simple log to the history list to aide in any troubleshooting

2. In my scenario I wanted to change the permissions of a specified group.  The rationale is that my library had given specific permissions e.g. contribute, however following initial page creation and the first edit of a page those permissions had to be downgraded to read only for the members of this permission group

3. In support of the above, this is the name of the permission that should be applied to the specified permission group

4. This is our first challenge, we need to use the SharePoint REST API to query the context information from our site collection.  The response to this request will contain the X-RequestDigest value which must be used for all future requests in this session.

The key task is correctly formatting the headers that need to be passed through with the request.  For me, the “unauthenticated Headers” are as follows:

Accept: application/json;odata=verbose
Content-Type: application/json;odata=verbose
Content-Length: 255

5. This action is where we actually call the appropriate SharePoint REST API.

The target location is [%Workflow Context:Current Site URL%]_api/contextinfo where the current site URL is simply an auto generated variable from the workflow context.

This HTTP call should be initiated using the HTTP POST method.

Once the service details have been populated, click OK and then click Properties

This is where we have the opportunity to specify our request headers saved in step #4 to be sent with this HTTP request.

6. Once we have the response back from SharePoint Online, we want to parse the data that was stored within postResponse and use a REST query to extract our Request Digest.

The query is simply d/GetContextWebInformation/FormDigestValue

7. The final stage in my process was to now build an authenticated set of headers for use within the rest of the workflow

Accept: application/json;odata=verbose
X-RequestDigest: <the digest value variable we saved in the previous action>
Content-length: 0
content-type: application/json;odata=verbose

Get group ID

The purpose of this stage is to get the internal ID of the group that we want to change the permissions for.

The specific background for each actions is as follows.

1. Simple log to the history list to aide in any troubleshooting

2. Call the REST API to obtain the group ID for the specified group that we set a variable for within the initialisation stage.

The target location is [%Workflow Context:Current Site URL%]_api/web/sitegroups/getbyname(‘[%Variable: targetGroupName%]’) where the current site URL is simply an auto generated variable from the workflow context.

This HTTP call should be initiated using the HTTP GET method.

Once the service details have been populated, click OK and then click Properties

This is where we have the opportunity to specify our request headers saved in step #7 of the previous stage.  From this point onwards in the workflow we are simply using the authenticatedHeaders now that we have our request digest value to send through with each request.

3. Off the back of the request, we need to parse the response and extract our group ID with d/Id

Get target role ID

The purpose of this stage is to obtain the ID for the permission / role level that we want to apply to the group obtained in the previous stage.

The specific background for each actions is as follows.

1. Simple log to the history list to aide in any troubleshooting

2. Call the REST API to obtain the role ID for the permission / role level that we set a variable for within the initialisation stage.

The target location is

[%Workflow Context:Current Site URL%]_api/web/roledefinitions/getbyname(‘[%Variable: targetRoleName%]’) where the current site URL is simply an auto generated variable from the workflow context.

This HTTP call should be initiated using the HTTP GET method.

Note that the process for all remaining HTTP web service details is the same, i.e. edit the properties as per the previous stage and make sure that the RequestHeaders being used are authenticatedHeaders.

To save some time, you could simply copy/paste the configured HTTP web service action and simply change the target location for each activity.

3. Off the back of the request, we need to parse the response and extract our role ID with d/Id

Break permissions inheritance

Before we can modify the permissions on the current list item, we first need to break the inheritance from its parent (in this case break inheritance from the list level permissions).

The specific background for each actions is as follows.

1. Simple log to the history list to aide in any troubleshooting

2. Call the REST API to break the permission inheritance on the item.

The target location is

[%Workflow Context:Current Site URL%]_api/web/GetFileByServerRelativeUrl(‘[%Current Item:Server Relative URL%]’)/ListItemAllFields/breakroleinheritance(true) where the current site URL is simply an auto generated variable from the workflow context.

This HTTP call should be initiated using the HTTP POST method.

Add temporary read permissions for initiator

This is one area where I ran into the most problems.  Logically, a workflow on the SharePoint platform is run as the initiator.  We partially work around this limitation through the use of the “App Step” method, however whilst an App Step enables actions to be run on an otherwise restrictive set of permissions – it still has its limitations.

If I run this workflow as a site collection administrator, the below stage is not required.  However, when a general user runs the workflow (even after using App Step), we run into a logical issue…

If we think back to the original problem statement, we want to modify the permissions for the group that the submitting user is part of.  At a high level we are essentially breaking inheritance, removing the existing permissions, and then applying the revised permissions.

When we otherwise remove the existing permissions, the workflow (running as the initiator) would get to this stage in the workflow and fail as it is no longer able to see/find the item that the workflow is running on (since we just removed permissions).

Instead, I chose to temporarily add permissions directly for the initiator against the item – then remove the group permissions that were previously giving access to the user, followed by adding the group permissions back in with the desired permissions.

By introducing direct level permissions, I mitigate the issue of the user not being able to see the item at this stage of the workflow process.

The specific background for each actions is as follows.

1. Simple log to the history list to aide in any troubleshooting

2. Set a variable which specifies the permission level we want to give the initiator temporarily

3. Call the REST API to obtain the role ID for the permission / role level that we just set above

The target location is

[%Workflow Context:Current Site URL%]_api/web/roledefinitions/getbyname(‘[%Variable: targetTempRoleName%]’) where the current site URL is simply an auto generated variable from the workflow context.

This HTTP call should be initiated using the HTTP GET method.

4. Off the back of the request, we need to parse the response and extract our role ID with d/Id

5. Call the REST API to assign the specified permissions (tempRoleID) to the current user.  Note that we don’t have to query for the current user ID as this is available natively within the workflow context.  Be sure to select the ID when assigning the [%Workflow Context:Initiator%] variable:

For the REST query, the target location is

[%Workflow Context:Current Site URL%]_api/web/GetFileByServerRelativeUrl(‘[%Current Item:Server Relative URL%]’)/ListItemAllFields/roleassignments/addroleassignment(principalid='[%Workflow Context:Initiator%]’,roledefid='[%Variable: tempRoleID%]’)

This HTTP call should be initiated using the HTTP GET method.

Remove current role assignment

This stage get us back on track for the core workflow process and will remove the existing group permissions from the list item.

The specific background for each actions is as follows.

1. Simple log to the history list to aide in any troubleshooting

2. Call the REST API to remove access for the specified group ID on the current item.

The target location is

[%Workflow Context:Current Site URL%]_api/web/GetFileByServerRelativeUrl(‘[%Current Item:Server Relative URL%]’)/ListItemAllFields/roleassignments/getbyprincipalid(‘[%Variable: groupID%]’) where the current site URL is simply an auto generated variable from the workflow context.

This HTTP call should be initiated using the HTTP DELETE method.

Add new role assignment

This stage adds our new permissions to the item for the specified group and role.

The specific background for each actions is as follows.

1. Simple log to the history list to aide in any troubleshooting

2. Call the REST API to remove access for the specified group ID on the current item.

The target location is

[%Workflow Context:Current Site URL%]_api/web/GetFileByServerRelativeUrl(‘[%Current Item:Server Relative URL%]’)/ListItemAllFields/roleassignments/addroleassignment(principalid='[%Variable: groupID%]’,roledefid='[%Variable: roleID%]’) where the current site URL is simply an auto generated variable from the workflow context.

This HTTP call should be initiated using the HTTP POST method.

Remove temporary read permissions

This stage simply undoes the temporary permissions that we added explicitly earlier for the current user.

The specific background for each actions is as follows.

1. Simple log to the history list to aide in any troubleshooting

2. Call the REST API to remove access for the specified group ID on the current item.

The target location is

[%Workflow Context:Current Site URL%]_api/web/GetFileByServerRelativeUrl(‘[%Current Item:Server Relative URL%]’)/ListItemAllFields/roleassignments/getbyprincipalid(‘[%Workflow Context:Initiator%]’) where the current site URL is simply an auto generated variable from the workflow context.

This HTTP call should be initiated using the HTTP DELETE method.

Conclusion

The above workflow will now trigger upon item creation and change the item level permissions for the specified group.

This would have only required a couple of actions within other specialist tools such as https://www.nintex.com however sometimes we are stuck with utilising the “free” tier of tooling.

Leave a Reply

Your email address will not be published. Required fields are marked *