What is ACS and why is it being retired?
Azure Access Control Service (ACS) is a legacy authentication service that allowed SharePoint Add-ins to obtain app-only access tokens. If you ever used the SharePoint pages /_layouts/15/appregnew.aspx to register an application and /_layouts/15/appinv.aspx to grant it permissions, you used ACS.
Important: ACS is not just about app-only tokens. Provider-hosted add-ins that run in a user context (user+app tokens) also go through ACS. If your frontend application redirects users through ACS to get a SharePoint access token, that flow will break too. Both app-only and user+app scenarios need to be migrated.
ACS was the standard approach for years. It was simple: you got a Client ID and Client Secret, and your code used those to obtain tokens. The problem? ACS is an old, limited service:
- Tenant-wide permissions only — you cannot scope access to specific site collections
- Client secrets expire — and when they do, your integration breaks silently
- No audit trail — limited visibility into what the application actually does
- No conditional access — no way to apply modern security policies
Microsoft officially retired ACS as a general Azure service back in November 2018, but kept the SharePoint-specific ACS endpoint (accounts.accesscontrol.windows.net) running. That grace period ends on April 2, 2026.
What will break on April 2, 2026
After the retirement date, the ACS token endpoint will stop issuing tokens. This means:
Will break
- Applications using
GetACSAppOnlyContext() - Azure Functions / WebJobs calling SharePoint via ACS tokens
- Power Automate custom connectors using ACS credentials
- Third-party tools configured with ACS Client ID + Secret
- Any code calling
TokenHelper.GetAppOnlyAccessToken() - Provider-hosted add-ins using ACS for user+app tokens (
TokenHelper.GetAccessToken())
Will NOT break
- Applications already using Microsoft Entra ID
- SharePoint Framework (SPFx) solutions
- Microsoft Graph API calls via Entra ID tokens
- User authentication via MSAL / Entra ID where no part of the chain uses ACS to call SharePoint
- SharePoint webhooks (they use Entra ID)
How to check if you are affected
Run this PowerShell command to list all ACS-registered apps in your tenant:
# Connect to SharePoint Online Management Shell
Connect-SPOService -Url https://yourtenant-admin.sharepoint.com
# List all ACS app principals
Get-SPOServicePrincipalPermissionGrant | Format-Table -AutoSizeIf this returns results, those applications need to be migrated.
Microsoft Entra ID: the replacement
Microsoft Entra ID (the new name for Azure Active Directory, or Azure AD) is the modern identity platform for all Microsoft 365 services. Instead of ACS client secrets, you use:
X.509 Certificates
The private key never leaves your server. More secure than shared secrets that can be copied.
Granular Permissions
Choose between Sites.Read.All, Sites.ReadWrite.All, Sites.FullControl.All, or Sites.Selected for scoped access.
Microsoft Graph
Access SharePoint through the unified Microsoft Graph API, or use the classic SharePoint REST/CSOM if needed.
ACS vs Entra ID at a glance
| ACS (old) | Entra ID (new) | |
|---|---|---|
| Authentication | Client ID + Secret | X.509 Certificate (recommended) |
| Permission scope | Entire tenant only | Tenant-wide or specific sites |
| API access | SharePoint CSOM/REST only | Microsoft Graph + SharePoint REST/CSOM |
| Audit / compliance | Limited | Full Entra ID sign-in logs |
| Conditional Access | Not supported | Fully supported |
| Status | Retiring April 2, 2026 | Active, recommended |
Option 1: Automatic migration with PnP PowerShell
The fastest way to register a new Entra ID application is PnP PowerShell. One command handles everything: app registration, certificate creation, certificate upload, and permission configuration.
Prerequisite: PowerShell 7+
PnP PowerShell requires PowerShell 7+ (pwsh). It does not work on the built-in Windows PowerShell 5.1. Install it with winget install Microsoft.PowerShell or download from Microsoft docs. Make sure to run all commands below in pwsh, not powershell.exe.
Step 1: Install PnP PowerShell
Install-Module -Name PnP.PowerShell -Scope CurrentUserStep 2: Register the Entra ID application
$app = Register-PnPAzureADApp \
-ApplicationName "Your App Name" \
-Store CurrentUser \
-Tenant yourtenant.onmicrosoft.com \
-Username "admin@yourtenant.onmicrosoft.com" \
-Password (Read-Host -AsSecureString -Prompt "Enter Password") \
-CertificatePassword (Read-Host -AsSecureString -Prompt "Enter Cert Password") \
-OutPath .\
# Save these — you will need them in your code
$app.'AzureAppId/ClientId'
$app.'Certificate Thumbprint'This single command:
- Registers the application in Entra ID
- Creates an X.509 certificate
- Imports the certificate into your Current User store
- Exports .PFX and .CER files to the output path
- Uploads the public key to Entra ID
- Configures default permissions (Sites.FullControl.All, User.ReadWrite.All)
Step 3: Grant admin consent
During registration, a consent dialog will appear. Approve it. If you missed it, go to the Azure Portal → Entra ID → App registrations → your app → API permissions → "Grant admin consent."
Customize permissions (optional)
# Example: only Sites.ReadWrite.All instead of FullControl
Register-PnPAzureADApp \
-ApplicationName "Your App Name" \
-Store CurrentUser \
-Tenant yourtenant.onmicrosoft.com \
-Username "admin@yourtenant.onmicrosoft.com" \
-Password (Read-Host -AsSecureString) \
-CertificatePassword (Read-Host -AsSecureString) \
-SharePointApplicationPermissions "Sites.ReadWrite.All" \
-GraphApplicationPermissions "Sites.ReadWrite.All" \
-OutPath .\Option 2: Manual migration in Azure Portal
If you need more control, or your organization requires manual approval for each step, here is the step-by-step process in the Azure Portal.
Step 1: Register the application
- Go to entra.microsoft.com
- Navigate to Identity → Applications → App registrations
- Click New registration
- Enter a name (e.g. "SharePoint Integration - Production")
- Choose Accounts in this organizational directory only (single-tenant)
- Click Register
- Note the Application (client) ID and Directory (tenant) ID
Step 2: Create and upload a certificate
Create a certificate with PnP PowerShell (or OpenSSL, or any other tool):
$cert = New-PnPAzureCertificate \
-CommonName "your-app-certificate" \
-OutPfx .\your-app.pfx \
-OutCert .\your-app.cer \
-ValidYears 2 \
-CertificatePassword (Read-Host -AsSecureString)
$cert.ThumbprintThen in the Azure Portal: your app → Certificates & secrets → Certificates tab → Upload certificate → select the .CER file.
Step 3: Configure API permissions
In the Azure Portal: your app → API permissions → Add a permission.
For SharePoint access, choose Application permissions (not delegated) from either:
Microsoft Graph
- Sites.Read.All
- Sites.ReadWrite.All
- Sites.Manage.All
- Sites.FullControl.All
SharePoint
- Sites.Read.All
- Sites.ReadWrite.All
- Sites.Manage.All
- Sites.FullControl.All
Step 4: Grant admin consent
In API permissions, click "Grant admin consent for [your tenant]". The status column should change to "Granted" with a green checkmark.
Code changes: before and after
If you use PnP Framework (the most common library for SharePoint CSOM), the code changes are minimal. Here is a side-by-side comparison.
Before (ACS) — stops working April 2, 2026
// ACS authentication — will break after April 2, 2026
var am = new AuthenticationManager();
using (var context = am.GetACSAppOnlyContext(
siteUrl,
clientId,
clientSecret)) // <-- shared secret
{
var list = context.Web.Lists.GetByTitle("Documents");
context.Load(list, l => l.Title);
await context.ExecuteQueryAsync();
Console.WriteLine(list.Title);
}After (Entra ID) — future-proof
// Entra ID authentication with X.509 certificate
var certificate = X509CertificateUtility.LoadCertificate(
StoreName.My,
StoreLocation.CurrentUser,
certificateThumbprint); // <-- certificate, not a secret
var am = AuthenticationManager.CreateWithCertificate(
clientId,
certificate,
tenantId);
using (var context = am.GetContext(siteUrl))
{
// Your CSOM code stays exactly the same
var list = context.Web.Lists.GetByTitle("Documents");
context.Load(list, l => l.Title);
await context.ExecuteQueryAsync();
Console.WriteLine(list.Title);
}What changed?
3 lines
Authentication setup is the only change
0 lines
CSOM business logic stays untouched
+1 param
tenantId is now required
Configuration changes
Update your application settings (appsettings.json, environment variables, or Azure Key Vault):
// Before (ACS)
{
"SharePoint": {
"SiteUrl": "https://yourtenant.sharepoint.com/sites/yoursite",
"ClientId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"ClientSecret": "your-acs-client-secret"
}
}
// After (Entra ID)
{
"SharePoint": {
"SiteUrl": "https://yourtenant.sharepoint.com/sites/yoursite",
"ClientId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"TenantId": "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy",
"CertificateThumbprint": "ABC123DEF456..."
}
}The Client Secret is gone. It is replaced by a Certificate Thumbprint (the certificate must be installed on the server running your code). You also need the Tenant ID now.
Migration checklist
- Inventory all ACS apps — run
Get-SPOServicePrincipalPermissionGrantto find all apps using ACS in your tenant - Register each app in Entra ID — use PnP PowerShell (fast) or Azure Portal (manual)
- Create and upload X.509 certificates — one per application, with a sensible expiration (2 years is common)
- Configure the minimum permissions needed — do not default to FullControl if ReadWrite will do
- Grant admin consent — permissions are not active until a Global Admin or Privileged Role Admin consents
- Update your code — swap ACS authentication for certificate-based Entra ID authentication
- Deploy the certificate — install the .PFX on all servers/environments running the app
- Test in a non-production tenant first — validate everything works before touching production
- Deploy to production — before April 2, 2026
- Remove old ACS registrations — clean up the old app principals to reduce your attack surface
FAQ
When does SharePoint ACS stop working?
April 2, 2026. After that date, ACS-based app-only tokens will no longer be issued. Any application relying on ACS for SharePoint Online access will stop working immediately.
What replaces ACS for SharePoint app-only access?
Microsoft Entra ID (formerly Azure AD). You register your application in Entra ID, configure an X.509 certificate for authentication, and use Microsoft Graph or SharePoint REST APIs with application permissions.
Do I need to change my CSOM code?
Only the authentication part. Replace GetACSAppOnlyContext() with AuthenticationManager.CreateWithCertificate(). All your CSOM logic (reading lists, uploading files, etc.) stays exactly the same.
Can I use client secrets instead of certificates?
Entra ID supports client secrets for some scenarios, but Microsoft recommends X.509 certificates for app-only access to SharePoint Online. Certificates are more secure — the private key never leaves your server.
Will this affect SharePoint On-Premise?
No. The ACS retirement only affects SharePoint Online. SharePoint On-Premise (2016, 2019, Subscription Edition) uses its own authentication mechanisms that are not impacted.
Need help with the migration?
The deadline is April 2, 2026. If you are starting the migration now, some downtime after the cutoff may be unavoidable — but the sooner you start, the shorter the outage. We have been migrating SharePoint solutions for enterprise clients for years and can help you get back on track as fast as possible.
