Use ACS to authorize low-trust provider-hosted add-ins on an on-premises SharePoint site
Important
The SharePoint Add-In model in SharePoint Online has been deprecated as of November 27th 2023, checkout the full retirement announcement to learn more.
Deprecation means that the feature will not get any new investments, but it's still supported. SharePoint add-in model is retired fully on April 2nd, 2026 and is no longer available after that time. Primary replacement technology for the SharePoint add-in model is SharePoint Framework (SPFx) which continues to be supported also in future.
Prerequisites
Be sure that you have the following:
An on-premises SharePoint development environment. See Set up an on-premises development environment for SharePoint Add-ins.
An Office 365 SharePoint site. If don't have one yet and you want to set up a development environment quickly, you can Set up a development environment for SharePoint Add-ins on Office 365.
Visual Studio installed either remotely or on a computer running SharePoint, with the workload Office/SharePoint development. Earlier versions of Visual Studio require component Microsoft Office Developer Tools for Visual Studio instead. The latest version of this component is available here for Visual Studio 2013, and here for Visual Studio 2015.
Important
ACS retirement in the Azure Active Directory side does not impact this functionality for SharePoint. See more details from following article - Impact of Azure Access Control retirement for SharePoint add-ins.
Configure your on-premises installation of SharePoint to use ACS
The following figure shows the four steps to enable the connections you need within the overall architecture of a provider-hosted add-in that runs on an on-premises site. It also shows the flow of OAuth tokens when the add-in is running.
Make ACS work with an on-premises installation of SharePoint by using an Office 365 SharePoint site
Create an ACS proxy in your on-premises SharePoint farm.
Install the signing certificate of your on-premises server to your Office 365 tenancy.
Add the fully qualified domain names of the sites on your SharePoint farm where you want to run add-ins to the service principal name collection in your Office 365 tenancy.
Create an add-in management proxy on your SharePoint farm.
The following function does all the work to configure your on-premises SharePoint site to use ACS. You can also use this function to do some cleanup tasks if you need to remove previous configurations. There are a variety of ways to run the function in PowerShell. The following is one method.
To configure your on-premises SharePoint site to use ACS
On the on-premises SharePoint server, copy the code of the function Connect-SPFarmToAAD (available below) into a text file named MySharePointFunctions.psm1, and save it to one or the other of the following folders (not both). You may have to create parts of the path, if it includes folders that do not already exist. Notice that in both cases, the lowest folder in the path has to have the same name as the file.
Tip
The file has to be saved as ANSI format, not UTF-8. PowerShell may give syntax errors when it loads a file with a non-ANSI format. Windows NotePad defaults to saving it as ANSI. If you use any other editor to save the file, be sure you are saving it as ANSI.
C:\users\username\documents\windowspowershell\modules\MySharePointFunctions
, where username is the farm administrator who is executing the file.C:\windows\system32\windowspowershell\V1.0\modules\MySharePointFunctions
Function Connect-SPFarmToAAD requires NuGet package MSOnlineExt to work, install it with the cmdlet below.
Install-Module -Name MSOnlineExt
Open the SharePoint Management Shell as an administrator and run the following cmdlet to verify that the MySharePointFunctions module is listed.
Get-Module -listavailable
Run the following cmdlet to import the module.
Import-Module MySharePointFunctions
Run the following cmdlet to verify that the Connect-SPFarmToAAD function is listed as part of the module.
Get-Command -module MySharePointFunctions
Run the following cmdlet to verify that the Connect-SPFarmToAAD function is loaded.
ls function:\ | where {$_.Name -eq "Connect-SPFarmToAAD"}
Run the
Connect-SPFarmToAAD
function. Be sure to provide the required parameters and any optional parameters that apply to your developer environment. See the next section for details and examples.
Connect-SPFarmToAAD function parameters
Parameter | Value |
---|---|
-AADDomain (required) |
The *.onmicrosoft.com domain that you created when you signed up for your Office 365 site (yourcustomdomain.onmicrosoft.com). When the script prompts you to authenticate, use the user name and password that you created for this domain: username@yourcustomdomain.onmicrosoft.com. |
-SharePointOnlineUrl (required) |
The URL of your Office 365 SharePoint site (_https://yourcustomdomain_.sharepoint.com ). Note that parent domain is not onmicrosoft.com. |
-SharePointWeb (sometimes required) |
The full URL (including protocol) of the on-premises SharePoint web application where you'll run provider-hosted add-ins. This function adds only one SharePoint web application from your on-premises farm to ACS. If you don't specify a value for this, the script selects the first web application in your farm. If you're using a Host Name Site Collection (HNSC) that can be defined with a wildcard (such as http://*.contoso.com), you can use that string as the value for this parameter. If the web application has an alternative access mapping (AAM) for the Internet zone, you must use that AAM URL for this parameter. If the SharePoint web application is not configured for HTTPS, you have to use HTTP as the protocol and you have to use the -AllowOverHttp switch (see later in this table). If you want to run provider-hosted add-ins that use ACS on more web applications in your farm, you need to add them to the service principal name collection. The Windows PowerShell script that follows the Connect-SPFarmToAAD function shows you how to add all the web applications on your farm to the service principal name collection. |
-AllowOverHttp (optional) |
Use this switch if you're working with a developer environment and don't want to use SSL with your add-ins. You have to use this switch if the SharePoint web application is not configured for HTTPS. |
-O365Credentials (optional) |
The first character is a capital "O", not a zero. If you find yourself repeatedly running the script for debugging purposes, this switch enables to you avoid having to manually enter your O365 name and password each time. Before you can use this parameter, you must create the credentials object that you will assign to it with these cmdlets: $User = "username@yourcustomdomain.onmicrosoft.com"$PWord = ConvertTo-SecureString -String "the_password" -AsPlainText -Force$Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $User, $PWord Use $Credential as the value of the -O365Credentials parameter. |
-Verbose (optional) |
This switch generates more detailed feedback that might help if the function is not working and you need to rerun it for debugging. |
-RemoveExistingACS (optional) |
Use this switch if you're replacing an existing connection to Azure Active Directory. It removes an existing ACS proxy if you've already created one on your farm. |
-RemoveExistingSTS (optional) |
Use this switch if you're replacing an existing connection to Azure Active Directory. It removes an existing trusted security token issuer that is left over from an earlier connection to ACS. |
-RemoveExistingSPOProxy (optional) |
Use this switch if you're replacing an existing connection to Azure Active Directory. It removes an existing add-in management proxy if you've already created one on your farm. |
-RemoveExistingAADCredentials (optional) |
Use this switch if you're replacing the Office 365 SharePoint site. |
The following are examples:
Connect-SPFarmToAAD -AADDomain 'MyO365Domain.onmicrosoft.com' -SharePointOnlineUrl https://MyO365Domain.sharepoint.com
Connect-SPFarmToAAD -AADDomain 'MyO365Domain.onmicrosoft.com' -SharePointOnlineUrl https://MyO365Domain.sharepoint.com -SharePointWeb https://fabrikam.com
Connect-SPFarmToAAD -AADDomain 'MyO365Domain.onmicrosoft.com' -SharePointOnlineUrl https://MyO365Domain.sharepoint.com -SharePointWeb http://northwind.com -AllowOverHttp
Connect-SPFarmToAAD -AADDomain 'MyO365Domain.onmicrosoft.com' -SharePointOnlineUrl https://MyO365Domain.sharepoint.com -SharePointWeb http://northwind.com -AllowOverHttp -RemoveExistingACS -RemoveExistingSTS -RemoveExistingSPOProxy -RemoveExistingAADCredentials
Content of MySharePointFunctions.psm1
function Connect-SPFarmToAAD {
param(
[Parameter(Mandatory)][String] $AADDomain,
[Parameter(Mandatory)][String] $SharePointOnlineUrl,
#Specify this parameter if you don't want to use the default SPWeb returned
[Parameter()][String] $SharePointWeb,
[Parameter()][System.Management.Automation.PSCredential] $O365Credentials,
#Use these switches if you're replacing an existing connection to AAD.
[Parameter()][Switch] $RemoveExistingACS,
[Parameter()][Switch] $RemoveExistingSTS,
[Parameter()][Switch] $RemoveExistingSPOProxy,
#Use this switch if you're replacing the Office 365 SharePoint site.
[Parameter()][Switch] $RemoveExistingAADCredentials,
#Use this switch if you don't want to use SSL when you launch your app.
[Parameter()][Switch] $AllowOverHttp
)
#Prompt for credentials right away.
if (-not $O365Credentials) {
$O365Credentials = Get-Credential -Message "Admin credentials for $AADDomain"
}
Add-PSSnapin Microsoft.SharePoint.PowerShell
#Import the Microsoft Online Services Sign-In Assistant.
Import-Module -Name MSOnline
#Import the Microsoft Online Services Module for Windows PowerShell.
Import-Module MSOnlineExt -force -verbose
#Set values for Constants.
New-Variable -Option Constant -Name SP_APPPRINCIPALID -Value '00000003-0000-0ff1-ce00-000000000000' | Out-Null
New-Variable -Option Constant -Name ACS_APPPRINCIPALID -Value '00000001-0000-0000-c000-000000000000' | Out-Null
New-Variable -Option Constant -Name ACS_APPPROXY_NAME -Value ACS
New-Variable -Option Constant -Name SPO_MANAGEMENT_APPPROXY_NAME -Value 'SPO Add-in Management Proxy'
New-Variable -Option Constant -Name ACS_STS_NAME -Value ACS-STS
New-Variable -Option Constant -Name AAD_METADATAEP_FSTRING -Value 'https://accounts.accesscontrol.windows.net/{0}/metadata/json/1'
New-Variable -Option Constant -Name SP_METADATAEP_FSTRING -Value '{0}/_layouts/15/metadata/json/1'
#Get the default SPWeb from the on-premises farm if no $SharePointWeb parameter is specified.
if ([String]::IsNullOrEmpty($SharePointWeb)) {
$SharePointWeb = Get-SPSite | Select-Object -First 1 | Get-SPWeb | Select-Object -First 1 | % Url
}
#Configure the realm ID for local farm so that it matches the AAD realm.
$ACSMetadataEndpoint = $AAD_METADATAEP_FSTRING -f $AADDomain
$ACSMetadata = Invoke-RestMethod -Uri $ACSMetadataEndpoint
$AADRealmId = $ACSMetadata.realm
Set-SPAuthenticationRealm -ServiceContext $SharePointWeb -Realm $AADRealmId
$LocalSTS = Get-SPSecurityTokenServiceConfig
$LocalSTS.NameIdentifier = '{0}@{1}' -f $SP_APPPRINCIPALID,$AADRealmId
$LocalSTS.Update()
#Allow connections over HTTP if the switch is specified.
if ($AllowOverHttp.IsPresent -and $AllowOverHttp -eq $True) {
$serviceConfig = Get-SPSecurityTokenServiceConfig
$serviceConfig.AllowOAuthOverHttp = $true
$serviceConfig.AllowMetadataOverHttp = $true
$serviceConfig.Update()
}
#Step 1: Set up the ACS proxy in the on-premises SharePoint farm. Remove the existing ACS proxy
#if the switch is specified.
if ($RemoveExistingACS.IsPresent -and $RemoveExistingACS -eq $True) {
Get-SPServiceApplicationProxy | ? DisplayName -EQ $ACS_APPPROXY_NAME | Remove-SPServiceApplicationProxy -RemoveData -Confirm:$false
}
if (-not (Get-SPServiceApplicationProxy | ? DisplayName -EQ $ACS_APPPROXY_NAME)) {
$AzureACSProxy = New-SPAzureAccessControlServiceApplicationProxy -Name $ACS_APPPROXY_NAME -MetadataServiceEndpointUri $ACSMetadataEndpoint -DefaultProxyGroup
}
#Remove the existing security token service if the switch is specified.
if ($RemoveExistingSTS.IsPresent) {
Get-SPTrustedSecurityTokenIssuer | ? Name -EQ $ACS_STS_NAME | Remove-SPTrustedSecurityTokenIssuer -Confirm:$false
}
if (-not (Get-SPTrustedSecurityTokenIssuer | ? DisplayName -EQ $ACS_STS_NAME)) {
$AzureACSSTS = New-SPTrustedSecurityTokenIssuer -Name $ACS_STS_NAME -IsTrustBroker -MetadataEndPoint $ACSMetadataEndpoint
}
#Update the ACS Proxy for OAuth authentication.
$ACSProxy = Get-SPServiceApplicationProxy | ? Name -EQ $ACS_APPPROXY_NAME
$ACSProxy.DiscoveryConfiguration.SecurityTokenServiceName = $ACS_APPPRINCIPALID
$ACSProxy.Update()
#Retrieve the local STS signing key from JSON metadata.
$SPMetadata = Invoke-RestMethod -Uri ($SP_METADATAEP_FSTRING -f $SharePointWeb)
$SPSigningKey = $SPMetadata.keys | ? usage -EQ "Signing" | % keyValue
$CertValue = $SPSigningKey.value
#Connect to Office 365.
Connect-MsolService -Credential $O365Credentials
#Remove existing connection to an Office 365 SharePoint site if the switch is specified.
if ($RemoveExistingAADCredentials.IsPresent -and $RemoveExistingAADCredentials -eq $true) {
$msolserviceprincipal = Get-MsolServicePrincipal -AppPrincipalId $SP_APPPRINCIPALID
[Guid[]] $ExistingKeyIds = Get-MsolServicePrincipalCredential -ObjectId $msolserviceprincipal.ObjectId -ReturnKeyValues $false | % {if ($_.Type -ne "Other") {$_.KeyId}}
Remove-MsolServicePrincipalCredential -AppPrincipalId $SP_APPPRINCIPALID -KeyIds $ExistingKeyIds
}
#Step 2: Upload the local STS signing certificate
New-MsolServicePrincipalCredential -AppPrincipalId $SP_APPPRINCIPALID -Type Asymmetric -Value $CertValue -Usage Verify
#Step 3: Add the service principal name of the local web application, if necessary.
$indexHostName = $SharePointWeb.IndexOf('://') + 3
$HostName = $SharePointWeb.Substring($indexHostName)
$NewSPN = '{0}/{1}' -f $SP_APPPRINCIPALID, $HostName
$SPAppPrincipal = Get-MsolServicePrincipal -AppPrincipalId $SP_APPPRINCIPALID
if ($SPAppPrincipal.ServicePrincipalNames -notcontains $NewSPN) {
$SPAppPrincipal.ServicePrincipalNames.Add($NewSPN)
Set-MsolServicePrincipal -AppPrincipalId $SPAppPrincipal.AppPrincipalId -ServicePrincipalNames $SPAppPrincipal.ServicePrincipalNames
}
#Remove the existing SharePoint Online proxy if the switch is specified.
if ($RemoveExistingSPOProxy.IsPresent -and $RemoveExistingSPOProxy -eq $True) {
Get-SPServiceApplicationProxy | ? DisplayName -EQ $SPO_MANAGEMENT_APPPROXY_NAME | Remove-SPServiceApplicationProxy -RemoveData -Confirm:$false
}
#Step 4: Add the SharePoint Online proxy
if (-not (Get-SPServiceApplicationProxy | ? DisplayName -EQ $SPO_MANAGEMENT_APPPROXY_NAME)) {
$spoproxy = New-SPOnlineApplicationPrincipalManagementServiceApplicationProxy -Name $SPO_MANAGEMENT_APPPROXY_NAME -OnlineTenantUri $SharePointOnlineUrl -DefaultProxyGroup
}
}
Configure the add-in and the SharePoint web application for the Office Store
There is an optional configuration step that farm administrators should take on production environments, if they want users to be able to install provider-hosted add-ins that use ACS from the Office Store. (It serves no purpose on your SharePoint development environment unless you plan to install add-ins that use ACS from the store on that environment.) The following cmdlet makes this possible. This code can be added to the preceding function.
New-SPMarketplaceWebServiceApplicationProxy -Name "ApplicationIdentityDataWebServiceProxy" -ServiceEndpointUri "https://oauth.sellerdashboard.microsoft.com/ApplicationIdentityDataWebService.svc" -DefaultProxyGroup
It is also a good practice on production SharePoint web applications to activate the Add-ins that require accessible internet facing endpoints feature after the configuration steps have been completed. (See the following instructions.) This feature does not actually do anything. It simply serves as a flag that tells the Office Store that provider-hosted add-ins that use ACS can be installed on websites in the SharePoint web application.
This system may have implications for the add-in manifest of your SharePoint Add-in. If you plan to sell your add-in through the store, it is a good practice to add the following AppPrerequisite to the AppPrerequisites section of the add-in manifest:
<AppPrerequisite Type="Feature" ID="{7877bbf6-30f5-4f58-99d9-a0cc787c1300}" />
The effect of the prerequisite is that when users are browsing the store from an on-premises SharePoint farm, your add-in is grayed-out and uninstallable when the parent SharePoint web application does not have the Add-ins that require accessible internet facing endpoints feature enabled. This ensures that you won't get complaints from customers who install your add-in to an on-premises SharePoint website and find that it does not work.
There are two ways to enable the feature. The first is to run the following PowerShell cmdlet (which can be added to the end of the preceding function) on any SharePoint server:
Enable-SPFeature -identity "7877bbf6-30f5-4f58-99d9-a0cc787c1300" -Url http://domain_of_the_SharePoint_web_application
The other way to enable the feature is to carry out the following steps in Central Administration:
In SharePoint Central Administration, go to Application Management > Manage web applications.
On the Manage Web Applications page, select the web application that you want to change.
On the ribbon, select Manage Features.
In the feature list, next to Add-ins that require accessible internet facing endpoints, select Activate.
Select OK.
Configure additional SharePoint web applications within the farm
If you have additional web applications on your SharePoint farm and you want to run provider-hosted add-ins that use ACS trust on them, you can use this Windows PowerShell script (in the SharePoint Management Shell) to add them to the service principal name collection.
$SPAppPrincipal = Get-MsolServicePrincipal -AppPrincipalId 00000003-0000-0ff1-ce00-000000000000
$id = "00000003-0000-0ff1-ce00-000000000000/"
Get-SPWebApplication | ForEach-Object {
$hostName = $_.Url.substring($_.Url.indexof("//") + 2)
$hostName = $hostName.Remove($hostName.Length - 1, 1)
$NewSPN = $id + $hostName
Write-Host "Adding SPN for" $NewSPN
if ($SPAppPrincipal.ServicePrincipalNames -notcontains $NewSPN) {
$SPAppPrincipal.ServicePrincipalNames.Add($NewSPN)
Set-MsolServicePrincipal -AppPrincipalId $SPAppPrincipal.AppPrincipalId -ServicePrincipalNames $SPAppPrincipal.ServicePrincipalNames
}
}