Skip to content

This Quickstart uses Azure Developer command-line (azd) tools to create functions for SharePoint Online

License

Notifications You must be signed in to change notification settings

Yvand/functions-quickstart-spo-azd

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

68 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

name description page_type languages products urlFragment
Azure Functions for SharePoint Online
This quickstart uses azd CLI to deploy Azure Functions which can connect to your own SharePoint Online tenant.
sample
azdeveloper
bicep
nodejs
typescript
azure-functions
sharepoint-online
functions-quickstart-spo-azd

Azure Functions for SharePoint Online

This quickstart is based on this repository. It uses Azure Developer command-line (azd) tools to deploy Azure Functions which can list, register and process SharePoint Online webhooks on your own tenant.
The Azure functions use the Flex Consumption plan, are written in TypeScript and run in Node.js 20.
The popular library PnPjs is used to interact with SharePoint.

Security of the Azure resources

The resources deployed in Azure are configured with a high level of security:

  • The functions service connects to the storage account and the key vault using a private endpoint.
  • No network access is allowed on the storage account and the key vault, except on specified IPs (configurable).
  • Authorization is configured using the functions service's managed identity (no access key or legacy access policy is enabled).

Prerequisites

Initialize the local project

You can initialize a project from this azd template in one of these ways:

  • Use this azd init command from an empty local (root) folder:

    azd init --template Yvand/functions-quickstart-spo-azd

    Supply an environment name, such as spofuncs-quickstart when prompted. In azd, the environment is used to maintain a unique deployment context for your app.

  • Clone the GitHub template repository, and create an azd environment (in this example, spofuncs-quickstart):

    git clone https://github.com/Yvand/functions-quickstart-spo-azd.git
    cd functions-quickstart-spo-azd
    azd env new spofuncs-quickstart

Prepare your local environment

  1. Add a file named local.settings.json in the root of your project with the following contents:

    {
       "IsEncrypted": false,
       "Values": {
          "AzureWebJobsStorage": "UseDevelopmentStorage=true",
          "FUNCTIONS_WORKER_RUNTIME": "node",
          "TenantPrefix": "YOUR_SHAREPOINT_TENANT_PREFIX",
          "SiteRelativePath": "/sites/YOUR_SHAREPOINT_SITE_NAME"
       }
    }
  2. Review the file infra\main.parameters.json to customize the parameters used for provisioning the resources in Azure. Review this article to manage the azd's environment variables.

    Important: Ensure the values for TenantPrefix and SiteRelativePath are identical between the files local.settings.json (used when running the functions locally) and infra\main.parameters.json (used to set the environment variables in Azure, while provisioning the resources using azd).

  3. Install the dependencies and build the functions app:

    npm install
    npm run build
  4. Provision the resources in Azure and deploy the functions app package by running command azd up.

  5. The functions can also be run locally by executing command npm run start.

Grant the functions access to SharePoint Online

The authentication to SharePoint is done using DefaultAzureCredential, so the credential used depends if the functions run on your local environment, or in Azure.
If you never heard about DefaultAzureCredential, you should familirize yourself with its concept by reading this article, before continuing.

Grant the functions access to SharePoint when they run on the local environment

DefaultAzureCredential will preferentially use the delegated credentials of Azure CLI to authenticate to SharePoint.
Use the Microsoft Graph PowerShell script below to grant the SharePoint delegated permission AllSites.Manage to the Azure CLI's service principal:

Connect-MgGraph -Scope "Application.Read.All", "DelegatedPermissionGrant.ReadWrite.All"
$scopeName = "AllSites.Manage"
$requestorAppPrincipalObj = Get-MgServicePrincipal -Filter "displayName eq 'Microsoft Azure CLI'"
$resourceAppPrincipalObj = Get-MgServicePrincipal -Filter "displayName eq 'Office 365 SharePoint Online'"

$params = @{
  clientId = $requestorAppPrincipalObj.Id
  consentType = "AllPrincipals"
  resourceId = $resourceAppPrincipalObj.Id
  scope = $scopeName
}
New-MgOauth2PermissionGrant -BodyParameter $params

Warning

The service principal for Azure CLI may not exist in your tenant. If so, check this issue to add it.

Important

AllSites.Manage is the minimum permission required to register a webhook. Sites.Selected cannot be used because it does not exist as a delegated permission in the SharePoint API.

Grant the functions access to SharePoint when they run in Azure

DefaultAzureCredential will use a managed identity to authenticate to SharePoint. This may be the existing, system-assigned managed identity of the functions service, or a user-assigned managed identity.
This tutorial will assume that the system-assigned managed identity is used.

Grant SharePoint API permission Sites.Selected to the managed identity

Navigate to the function apps in the Azure portal > Select your app > Identity. Note the Object (principal) ID of the system-assigned managed identity.
In this tutorial, it is d3e8dc41-94f2-4b0f-82ff-ed03c363f0f8.
Then, use one of the scripts below to grant it the app-only permission Sites.Selected on the SharePoint API:

Using Microsoft Graph PowerShell
Connect-MgGraph -Scope "Application.Read.All", "AppRoleAssignment.ReadWrite.All"
$managedIdentityObjectId = "d3e8dc41-94f2-4b0f-82ff-ed03c363f0f8" # 'Object (principal) ID' of the managed identity
$scopeName = "Sites.Selected"
$resourceAppPrincipalObj = Get-MgServicePrincipal -Filter "displayName eq 'Office 365 SharePoint Online'" # SPO
$targetAppPrincipalAppRole = $resourceAppPrincipalObj.AppRoles | ? Value -eq $scopeName

$appRoleAssignment = @{
    "principalId" = $managedIdentityObjectId
    "resourceId"  = $resourceAppPrincipalObj.Id
    "appRoleId"   = $targetAppPrincipalAppRole.Id
}
New-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $managedIdentityObjectId -BodyParameter $appRoleAssignment | Format-List
Using az cli in Bash
managedIdentityObjectId="d3e8dc41-94f2-4b0f-82ff-ed03c363f0f8" # 'Object (principal) ID' of the managed identity
resourceServicePrincipalId=$(az ad sp list --query '[].[id]' --filter "displayName eq 'Office 365 SharePoint Online'" -o tsv)
resourceServicePrincipalAppRoleId="$(az ad sp show --id $resourceServicePrincipalId --query "appRoles[?starts_with(value, 'Sites.Selected')].[id]" -o tsv)"

az rest --method POST --uri "https://graph.microsoft.com/v1.0/servicePrincipals/${managedIdentityObjectId}/appRoleAssignments" --headers 'Content-Type=application/json' --body "{ 'principalId': '${managedIdentityObjectId}', 'resourceId': '${resourceServicePrincipalId}', 'appRoleId': '${resourceServicePrincipalAppRoleId}' }"

Grant effective permission on a SharePoint site to the managed identity

Navigate to the Enterprise applications in the Entra ID portal > Set the filter Application type to Managed Identities > Click on your managed identity and note its Application ID.
In this tutorial, it is 3150363e-afbe-421f-9785-9d5404c5ae34.

Warning

In this step, we will use the Application ID of the managed identity, while in the previous step we used its Object ID, be mindful about the risk of confusion.

Then, use one of the scripts below to grant it the app-only permission manage on a specific SharePoint site:

Using PnP PowerShell

PnP PowerShell

Connect-PnPOnline -Url "https://YOUR_SHAREPOINT_TENANT_PREFIX.sharepoint.com/sites/YOUR_SHAREPOINT_SITE_NAME" -Interactive -ClientId "YOUR_PNP_APP_CLIENT_ID"
Grant-PnPAzureADAppSitePermission -AppId "3150363e-afbe-421f-9785-9d5404c5ae34" -DisplayName "YOUR_FUNC_APP_NAME" -Permissions Manage
Using m365 cli in Bash

m365 cli

targetapp="3150363e-afbe-421f-9785-9d5404c5ae34"
siteUrl="https://YOUR_SHAREPOINT_TENANT_PREFIX.sharepoint.com/sites/YOUR_SHAREPOINT_SITE_NAME"
m365 spo site apppermission add --appId $targetapp --permission manage --siteUrl $siteUrl

Important

manage is the minimum permission required to register a webhook.

Call the functions

For security reasons, when running in Azure, functions require an app key to pass in query string parameter code. The app keys can be found in the functions app service > App Keys.
Most functions take optional parameters tenantPrefix and siteRelativePath. If they are not specified, the values set in the app's environment variables will be used.

Using vscode extension RestClient

You can use the Visual Studio Code extension REST Client to execute the requests in the .http files.
They require parameters from a .env file on the same folder. You can create it based on the sample files azure.env.example and local.env.example.

Using curl

Below is a sample script in Bash that calls the functions in Azure using curl:

# Edit those variables to fit your app function
funchost="YOUR_FUNC_APP_NAME"
code="YOUR_HOST_KEY"
notificationUrl="https://${funchost}.azurewebsites.net/api/webhook/service?code=${code}"
listTitle="YOUR_SHAREPOINT_LIST"

# List all webhooks on a list
curl --location "https://${funchost}.azurewebsites.net/api/webhook/list?code=${code}&listTitle=${listTitle}"

# Register a webhook
curl -X POST --location "https://${funchost}.azurewebsites.net/api/webhook/register?code=${code}&listTitle=${listTitle}&notificationUrl=${notificationUrl}"

# Show this webhook registered on a list
curl --location "https://${funchost}.azurewebsites.net/api/webhook/show?code=${code}&listTitle=${listTitle}&notificationUrl=${notificationUrl}"

# Remove the webhook from the list
# You can get the webhook id in the output of the function /webhook/show above
webhookId="5964efeb-c797-4b2d-a911-c676b942511f"
curl -X POST --location "https://${funchost}.azurewebsites.net/api/webhook/remove?code=${code}&listTitle=${listTitle}&webhookId=${webhookId}"

Review the logs

When the functions run in your local environment, the logging goes to the console.
When the functions run in Azure, the logging goes to the Application Insights resource configured in the app service.

KQL queries for Application Insights

The KQL query below shows the messages from all the functions, and filters out the logging from the infrastructure:

traces 
| where isnotempty(operation_Name)
| project timestamp, operation_Name, severityLevel, message

The KQL query below shows the messages only from the function webhook/service (which receives the notifications from SharePoint):

traces 
| where operation_Name contains "webhook-service"
| project timestamp, operation_Name, severityLevel, message

Known issues

Azure Functions Flex Consumption plan is currently in preview, be aware about its current limitations and issues.

About

This Quickstart uses Azure Developer command-line (azd) tools to create functions for SharePoint Online

Resources

License

Stars

Watchers

Forks

Packages

No packages published