For a decade, the way to extend SharePoint was a farm solution: a WSP package containing assemblies deployed to the Global Assembly Cache, running with full trust inside the SharePoint worker process. It was powerful and dangerous in equal measure. With Office 365 and SharePoint Online, that model simply doesn't exist — there is no server you can deploy a DLL to. This article explains why the SharePoint Add-in model replaced it, how provider-hosted add-ins authenticate, and how to approach migrating real code.

Why full-trust had to go

Farm solutions execute in-process with SharePoint. That means a memory leak, an undisposed SPSite, or a blocking web-service call in your code degrades the entire farm — for every tenant on it. In a multi-tenant cloud, that is unacceptable. Microsoft's answer was to move custom code out of the SharePoint process entirely:

Two add-in flavours

The add-in model comes in two shapes:

How provider-hosted authentication works

A provider-hosted add-in authenticates to SharePoint Online through Azure Access Control Service (ACS) using OAuth. The high-level flow:

  1. You register the add-in (via AppRegNew.aspx or the Seller Dashboard) and receive a client ID and client secret.
  2. When a user launches the add-in, SharePoint posts a context token to your remote web.
  3. Your code validates that token and exchanges it (with ACS) for an access token scoped to the user and site.
  4. You attach the access token to CSOM/REST calls back into SharePoint.

The Visual Studio add-in template ships a TokenHelper class and SharePointContext that do the heavy lifting:

// Provider-hosted add-in: get an authenticated ClientContext
protected void Page_Load(object sender, EventArgs e)
{
    var spContext =
        SharePointContextProvider.Current.GetSharePointContext(Context);

    using (var ctx = spContext.CreateUserClientContextForSPHost())
    {
        ctx.Load(ctx.Web, w => w.Title);
        ctx.ExecuteQuery();
        lblTitle.Text = ctx.Web.Title;
    }
}
CreateUserClientContextForSPHost() acts as the signed-in user (low-trust user+app token). For background jobs with no user present, use an app-only token instead — but app-only requires the permission to be explicitly granted at registration time.

Declaring permissions

An add-in has no rights by default. You request exactly the scopes you need in AppManifest.xml, and an administrator (or site owner) consents at install time. Least privilege is the rule:

<AppPermissionRequests AllowAppOnlyPolicy="true">
  <AppPermissionRequest
      Scope="http://sharepoint/content/sitecollection/web"
      Right="Write" />
</AppPermissionRequests>

Scopes range from tenant down through sitecollection, web, and list, with rights of Read, Write, Manage, and FullControl. Request the narrowest scope and lowest right that gets the job done.

A pragmatic migration strategy

You rarely "lift and shift" a farm solution — the architecture is fundamentally different. Instead, decompose the old WSP by capability and map each to its modern equivalent:

Farm solution featureAdd-in model replacement
Server-side event receiversRemote event receivers / webhooks
Web parts (visual)Add-in part (client web part) or, later, SPFx
Custom ribbon / actionsCustom actions declared in the add-in manifest
Timer jobsExternal scheduled service (Azure WebJob / Function)
Feature receivers / provisioningRemote provisioning via CSOM (PnP)
Full-trust business logicProvider-hosted web app calling CSOM/REST
The PnP (Patterns & Practices) remote provisioning engine is your friend here. Instead of feature XML, you extract a site as a template and re-apply it with CSOM from outside — the same business outcome, no server-side code.

Refactor in layers

  1. Isolate the business logic from the SharePoint plumbing in the old solution. Pure C# rules and calculations move across almost unchanged.
  2. Replace the data layer — swap server SPListItem calls for client-side CSOM/REST against the same lists.
  3. Re-home the entry points — event receivers become remote receivers/webhooks; timer jobs become scheduled Azure jobs; UI becomes add-in parts.
  4. Re-implement provisioning with PnP templates rather than feature activation.

Looking ahead

The add-in model itself was a transitional architecture. By the time you read the later articles in this series, SPFx had become the recommended way to build UI, and Microsoft Graph plus Azure AD app registrations replaced ACS for authentication (ACS-based app-only auth is now on a deprecation path). But the core lesson endures: in the cloud, your code lives outside SharePoint and earns access through explicit, least-privilege permissions. Internalising that during the farm-to-add-in transition is exactly what makes the later jump to Graph feel natural.

DS

Dhaval Shah

Cloud Solution Architect — 18+ years across SharePoint, Microsoft 365, and Azure AI.