Skip to content

Commit ee5ef08

Browse files
committed
RER updates
1 parent cb73691 commit ee5ef08

File tree

3 files changed

+160
-4
lines changed

3 files changed

+160
-4
lines changed

docs/sp-add-ins-modernize/from-remote-event-receivers-to-webhooks.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
title: Transform SharePoint Add-in model Remote Event Receivers to SharePoint Online Webhooks
33
description: Transform SharePoint Add-in model Remote Event Receivers to SharePoint Online Webhooks.
4-
ms.date: 08/28/2023
4+
ms.date: 03/15/2024
55
ms.localizationpriority: high
66
ms.service: sharepoint
77
---
@@ -12,7 +12,10 @@ In the SharePoint Add-in model you can create Remote Event Receivers, which can
1212

1313
The synchronous events allow a developer to intercept an event while it is happening and with custom logic the Remote Event Receiver can even cancel the currently running operation.
1414

15-
The asynchronous events allow a developer to be notified of an event after it already occured, as such you can only keep track of the event or react to the event, but you cannot cancel the already occurred event, unless you implement your own compensation logic. Due to their nature and logic, the synchronous events are often called *-ing* events (ItemAdding, ItemUpdating, ItemDeleting, etc.), while the asynchronous events are often called *-ed* events (ItemAdded, ItemUpdated, ItemDeleted, etc.).
15+
The asynchronous events allow a developer to be notified of an event after it already occurred, as such you can only keep track of the event or react to the event, but you cannot cancel the already occurred event, unless you implement your own compensation logic. Due to their nature and logic, the synchronous events are often called *-ing* events (ItemAdding, ItemUpdating, ItemDeleting, etc.), while the asynchronous events are often called *-ed* events (ItemAdded, ItemUpdated, ItemDeleted, etc.).
16+
17+
> [!Important]
18+
> Remote Event Receivers can also be used without having a dependency on Azure ACS (which is retired), check the [Use remote event receivers without Azure ACS dependency](./use-remote-event-receivers-without-azure-acs-dependency.md) article to learn more.
1619
1720
> [!IMPORTANT]
1821
> This article refers to so called PnP components, samples and/or tooling which are open-source assets backed by an active community providing support for them. There is no SLA for open-source tool support from official Microsoft support channels. These components or samples are however using Microsoft supported out of the box APIs and features which are supported by Microsoft.
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
---
2+
title: Registering and using Remote Event Receivers without having a dependency on Azure ACS
3+
description: Explains how Remote Event Receivers can be registered using an Entra application (Azure AD) and as such are not dependent on Azure ACS.
4+
ms.date: 03/14/2024
5+
ms.localizationpriority: high
6+
ms.service: sharepoint
7+
---
8+
9+
# Registering and using Remote Event Receivers without having a dependency on Azure ACS
10+
11+
The classical usage of Remote Event Receivers, which we'll name RERs in the remainder of this page, is strongly tied to Azure ACS. Key RER use cases are being part of a provider hosted SharePoint Add-Ins or being used outside of SharePoint Add-Ins by registering them using an Azure ACS principal as authentication means. With the announced [retirement of Azure ACS](https://aka.ms/retirement/acs/support) and the [retirement of SharePoint Add-Ins](https://aka.ms/retirement/addins/support), RERs depending on Azure ACS will stop working as they'll follow the outlined Azure ACS retirement path.
12+
13+
However, there's an option to use RERs via an Entra application, so without having a dependency on Azure ACS. In the coming chapters you'll learn how to configure the Entra app for registering the RERs and you'll learn more about the differences between a RER registered using Azure ACS versus one registered using an Entra app.
14+
15+
> [!Important]
16+
> Although these RERs do not depend on Azure ACS they still will retire, the main difference is that they'll keep working until July 1, 2027 and that they'll also work for new tenants onboarding after November 1, 2024. RERs depending on Azure ACS will follow the Azure ACS retirement path, so they'll stop working on April 2, 2026 and for new tenants onboarding after November 1, 2024 they'll not work anymore.
17+
18+
## Step 1: Configure your Entra application for registering a RER
19+
20+
It's required for the Entra application that's used to register the RERs to be configured with the `sites.selected` permission role. Follow this [blog post](https://techcommunity.microsoft.com/t5/microsoft-sharepoint-blog/develop-applications-that-use-sites-selected-permissions-for-spo/ba-p/3790476) to learn more on how to configure your Entra app. In our case, since the registration of RERs requires SharePoint REST/CSOM APIs it's important to also add the SharePoint `sites.selected` role and to configure the application with a certificate as the `sites.selected` role only is there when application permissions are used. Calling the SharePoint REST/CSOM APIs using application permissions requires the use of a certificate.
21+
22+
## Step 2: Register a RER using your Entra application
23+
24+
Once the Entra application is ready use it to authenticate to SharePoint using application permissions followed by using the SharePoint REST/CSOM APIs to register the RERs you need. You can for example do a POST to `_api/Web/EventReceivers` or use the equivalent CSOM `EventReceivers` collection of a `Web` and add a new one. If you prefer to use PnP PowerShell then below snippet can be used:
25+
26+
```PowerShell
27+
# Connect via the created Entra app using application permissions
28+
Connect-PnPOnline https://contoso.sharepoint.com/sites/testsite -ClientId 3b9ad858-dbbb-489b-b63d-1905426222f8 -Tenant contoso.onmicrosoft.com -CertificatePath ".\RERApp.pfx"
29+
30+
# Add a RER for synchronous firing on item add. This RER is calling a ngrok URL to proxy back to an Azure function running on localhost
31+
Add-PnPEventReceiver -List "MyList" -Name "RER-HelloWorld-ItemAdding" -Url "https://0051-84-195-208-70.ngrok-free.app/api/Service1" -SequenceNumber 10000 -EventReceiverType ItemAdding -Synchronization Synchronous
32+
33+
# List all added RERs
34+
Get-PnPEventReceiver -List "MyList"
35+
36+
# Delete a RER
37+
Remove-PnPEventReceiver -List "MyList" -Identity "<replace by RER guid from previous command output"
38+
```
39+
40+
## Step 3: Learn more about the difference between a RER registered using an Entra application with sites.selected versus a RER registered using Azure ACS
41+
42+
When a RER is registered using en Entra app with `sites.selected` it will fire for both synchronous and asynchronous events, but there is a key difference to be aware of: when your RER service is called you'll not receive a `ContextToken` anymore. Consequence is that your RER service cannot impersonate the user that triggered the RER to fire but it has to use application permissions to call back to SharePoint.
43+
44+
Below snippet shows the payload sent to your service, notice the "empty" `ContextToken` element and the "GetContextTokenError value for the `ErrorCode` element.
45+
46+
```xml
47+
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
48+
<s:Body>
49+
<ProcessOneWayEvent xmlns="http://schemas.microsoft.com/sharepoint/remoteapp/">
50+
<properties xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
51+
<AppEventProperties i:nil="true"/>
52+
<ContextToken/>
53+
<CorrelationId>25c1f6a0-e0d9-7000-ce2b-c721e30ad4bd</CorrelationId>
54+
<CultureLCID>2067</CultureLCID>
55+
<EntityInstanceEventProperties i:nil="true"/>
56+
<ErrorCode>GetContextTokenError</ErrorCode>
57+
<ErrorMessage>The endpoint address 'https://0f68-84-195-208-70.ngrok-free.app/api/Service1' does not match the app's endpoint 'www.contoso.com'.</ErrorMessage>
58+
<EventType>ItemAdded</EventType>
59+
<ItemEventProperties>
60+
<AfterProperties xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
61+
<a:KeyValueOfstringanyType>
62+
<a:Key>TimesInUTC</a:Key>
63+
<a:Value i:type="b:string"
64+
xmlns:b="http://www.w3.org/2001/XMLSchema">TRUE</a:Value>
65+
</a:KeyValueOfstringanyType>
66+
<a:KeyValueOfstringanyType>
67+
<a:Key>ContentType</a:Key>
68+
<a:Value i:type="b:string"
69+
xmlns:b="http://www.w3.org/2001/XMLSchema">Item</a:Value>
70+
</a:KeyValueOfstringanyType>
71+
<a:KeyValueOfstringanyType>
72+
<a:Key>Title</a:Key>
73+
<a:Value i:type="b:string"
74+
xmlns:b="http://www.w3.org/2001/XMLSchema">demo1</a:Value>
75+
</a:KeyValueOfstringanyType>
76+
<a:KeyValueOfstringanyType>
77+
<a:Key>FileSystemObjectType</a:Key>
78+
<a:Value i:type="b:string"
79+
xmlns:b="http://www.w3.org/2001/XMLSchema">File</a:Value>
80+
</a:KeyValueOfstringanyType>
81+
</AfterProperties>
82+
<AfterUrl i:nil="true"/>
83+
<BeforeProperties xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays"/>
84+
<BeforeUrl/>
85+
<CurrentUserId>6</CurrentUserId>
86+
<ExternalNotificationMessage i:nil="true"/>
87+
<IsBackgroundSave>false</IsBackgroundSave>
88+
<ListId>1814779c-276b-4380-adaa-42794f7d08c3</ListId>
89+
<ListItemId>2</ListItemId>
90+
<ListTitle>RER</ListTitle>
91+
<UserDisplayName>Joe Doe</UserDisplayName>
92+
<UserLoginName>i:0#.f|membership|[email protected]</UserLoginName>
93+
<Versionless>false</Versionless>
94+
<WebUrl>https://contoso.sharepoint.com/sites/testsite</WebUrl>
95+
</ItemEventProperties>
96+
<ListEventProperties i:nil="true"/>
97+
<SecurityEventProperties i:nil="true"/>
98+
<UICultureLCID>1033</UICultureLCID>
99+
<WebEventProperties i:nil="true"/>
100+
</properties>
101+
</ProcessOneWayEvent>
102+
</s:Body>
103+
</s:Envelope>
104+
```
105+
106+
## Step 4: Code sample to help you understand how to use RERs
107+
108+
RERs can be implemented as modern .NET solutions using Azure Functions, below snippet shows a RER implementation that rejects an item add as part of a synchronous ItemAdding event.
109+
110+
```csharp
111+
using System;
112+
using System.IO;
113+
using System.Threading.Tasks;
114+
using Microsoft.AspNetCore.Mvc;
115+
using Microsoft.Azure.WebJobs;
116+
using Microsoft.Azure.WebJobs.Extensions.Http;
117+
using Microsoft.AspNetCore.Http;
118+
using Microsoft.Extensions.Logging;
119+
using Newtonsoft.Json;
120+
using System.Net;
121+
122+
namespace AzureFunctionRER
123+
{
124+
public static class Service1
125+
{
126+
127+
private static string cancelResponse = "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"><s:Body><ProcessEventResponse xmlns=\"http://schemas.microsoft.com/sharepoint/remoteapp/\"><ProcessEventResult xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\"><ChangedItemProperties xmlns:a=\"http://schemas.microsoft.com/2003/10/Serialization/Arrays\"/><ErrorMessage>You shall not pass!</ErrorMessage><RedirectUrl i:nil=\"true\"/><Status>CancelWithError</Status></ProcessEventResult></ProcessEventResponse></s:Body></s:Envelope>";
128+
129+
[FunctionName("Service1")]
130+
public static async Task<IActionResult> Run(
131+
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
132+
ILogger log)
133+
{
134+
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
135+
136+
// For cancelling a sync event
137+
return new ContentResult
138+
{
139+
Content = cancelResponse,
140+
ContentType = "text/xml",
141+
StatusCode = (int)HttpStatusCode.InternalServerError
142+
};
143+
144+
// For accepting the sync event
145+
//string responseMessage = string.IsNullOrEmpty(name)
146+
// ? "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response."
147+
// : $"Hello, {name}. This HTTP triggered function executed successfully.";
148+
149+
//return new OkObjectResult(responseMessage);
150+
}
151+
}
152+
}
153+
```

docs/sp-add-ins/add-ins-and-azure-acs-retirements-faq.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@ Yes, remote event receivers are part of this retirement. Remote event receivers
4949

5050
As webhooks are asynchronous by definition, synchronous events that allow an app to block or cancel a SharePoint action are no longer possible. If event blocking is being used to prevent accidental data updates/deletes by unauthorized users, then possible workarounds are securing the protected files/folders so they cannot be updated/deleted anymore, or by moving this type of data to a hidden library. In general, moving from synchronous to asynchronous events will require updating your application logic.
5151

52-
> [!Note]
53-
> It's possible to get remote event receivers to partly work without Azure ACS by using sites.selected. This approach is **not** recommended, and will stop working when Azure ACS fully retires in April 2026.
52+
> [!Important]
53+
> We strongly recommend to switch to webhooks over remote event receivers, but we do also support remote event receivers registered using an Entra application. These remote event receivers will follow a slightly different retirement path: they'll stay working until July 1, 2027 whereas the remote event receivers registered using Azure ACS will stop working on April 2, 2026. Furthermore, these event receivers will still work for new tenants onboarding after November 1, 2024 whereas remote event receivers registered using Azure ACS will not work anymore. Check the [Use remote event receivers without Azure ACS dependency](../sp-add-ins-modernize/use-remote-event-receivers-without-azure-acs-dependency.md) article to learn more.
5454
5555
## Can I still perform taxonomy updates?
5656

0 commit comments

Comments
 (0)