It’s Free to Read Sensitivity Labels, But Assigning Sensitivity Labels Requires Payment

In early 2023, Microsoft introduced Graph APIs to read and apply sensitivity labels. In an article published after the APIs became available, I describe how to use the extractSensitivityLabels API to read sensitivity label information for Office documents and PDFs stored in SharePoint Online. Since then, I’ve used the API to report sensitivity label information in other scripts, including one to generate a report about files stored in a SharePoint Online document library. All in all, there’s no issue in finding sensitivity labels assigned to files.

Assigning sensitivity labels to files is a different matter. Microsoft is quite happy for tenants to read and report sensitivity labels that are in place, but they consider the assignSensitivityLabel API to be an “advanced API.” When I wrote my 2023 article, securing approval to use the API required going through some contortions with Microsoft bureaucracy, and I gave up after wasting several hours with zero results.

Enabling Protected APIs

The process is easier now because Microsoft now allows tenants to use advanced APIs by enabling apps that run the APIs by associating the apps with Azure subscriptions. Apparently, paying to use an advanced API is considered the “additional validation, beyond permission and consent, before you can use them.

The full set of metered APIs is documented online. Currently, the set comprises the APIs needed to backup/export Teams chat and channel conversations (high-capacity APIs), Teams change notifications, and the API to assign sensitivity labels to files.

Working Out How to Assign Sensitivity Labels

As we all know, there’s plenty new in Microsoft 365 to keep anyone fully occupied, so I didn’t go back to test the assignSensitivityLabel API. But loyal readers of this website prompted for more information. The only answer was to break out Visual Studio code and consult the documentation for the assignSensitivityLabel API.

Linking an Entra ID App with an Azure Subscription

The first thing you’ll need is a suitable Entra ID app registration. You can reuse an app or create a new one. The app serves two purposes. Its service principal holds the permissions needed to interact with data (the content of SharePoint Online sites in this case) and the app identifier is how Azure knows that the app is authorized to use the metered API. The app needs an X.509 certificate to authenticate. Make sure that the app has consent to use the Sites.ReadWrite.All application permission as the app needs to be able to update documents in document libraries.

The next step is to link the app registration with an Azure subscription. The link allows Microsoft to charge for any calls the app makes to the metered API. If a suitable resource group doesn’t exist in the Azure subscription, you’ll need to create one before linking the app to the subscription. You’ll also need to know the GUIDs for the app and the Azure subscription.

Here’s the command I entered in the Azure cloud shell to create the association. It’s easier to prepare the command in a text editor and then paste it into the cloud shell (use CTRL-Shift-V). Figure 1 shows the response.

az resource create --resource-group SensitivityLabels --name AssignLabels --resource-type Microsoft.GraphServices/accounts --properties "{""appId"": ""43685887-266e-46cf-915b-ea69bd84fe25""}" --location Global --subscription 35429342-a1a5-4427-9a2d-551840f2ed25
 Associating an Entra ID app with an Azure subscription.
Figure 1: Associating an Entra ID app with an Azure subscription

Failure to associate an app with an Azure subscription before using it to run a metered API results in 402 errors.

Choosing a Sensitivity Label to Apply

Now that we have an app with the right permissions linked to an Azure subscription, we can find some documents to label. When you call the assignSensitivityLabel API, the code must pass the immutable identifier for the label to assign. You can find this information in two ways:

  1. Connect to Exchange Online and then the compliance endpoint and run the Get-Label cmdlet. The cmdlet returns all known sensitivity labels in the tenant. Some of the labels might be solely used for container management. Only labels available for application to files can be used with the assignSensitivityLabel API.
  2. Run the Get-MgBetaUserSecurityInformationProtectionSensitivityLabel cmdlet from the Microsoft Graph PowerShell SDK. This is the equivalent of running the List sensitivity labels Graph API and returns the set of labels published to the signed-in user.

Here’s an example of using the Get-Label cmdlet to find sensitivity labels that you can apply to files:

Connect-ExchangeOnline
Connect-IPPSSession
[array]$Labels = Get-Label | Where-Object {$_.ContentType -like "*File*"}
$Labels | Format-Table ImmutableId, DisplayName

ImmutableId                          DisplayName
-----------                          -----------
2fe7f66d-096a-469e-835f-595532b63560 Public
8b652c9a-a8b7-40ec-bb1a-c5334b1b7fef No Encryption
fb0975b2-1ea1-4c3c-850c-e859e690d282 Partner-Accessible Content
27451a5b-5823-4853-bcd4-2204d03ab477 Internal

Connecting to the Graph

To use a metered API, we need to connect to the Microsoft Graph PowerShell SDK using the identifier of the application associated with the Azure subscription. The connection request also passes the tenant identifier (to tell the Graph which tenant to use) and the thumbprint of the certificate loaded into the app. Here’s the connection command:

Connect-MgGraph -NoWelcome -AppId $AppId -TenantId $TenantId -CertificateThumbprint $CertThumbprint

Running the Get-MgContext cmdlet afterward should reveal that the connection authentication is AppOnly (meaning that application permissions are used) together with the scopes (permissions) available to the app. In this instance, we see that Sites.ReadWrite.All permission is available. This permission allows the app to read and write data in any SharePoint Online site in a tenant (write access is needed to update a file with a label).

Get-MgContext

ClientId               : 43685887-266e-46cf-915b-ea69bd84fe25
TenantId               : a662313f-14fc-43a2-9a7a-d2e27f4f3478
Scopes                 : {Sites.ReadWrite.All}
AuthType               : AppOnly
TokenCredentialType    : ClientCertificate
CertificateThumbprint  : F79286DB88C21491110109A0222348FACF694CBD
CertificateSubjectName :
SendCertificateChain   : False
Account                :
AppName                : AssignSensitivityLabels

From this point, the code needs to find a target site, select a drive in the site, and find the files in the drive. All of this is done with standard Graph commands like those used to in the script described in the article about how to report the contents of a document library.

I refactored that script to assign sensitivity labels to supported files that don’t already have labels. You can download the script to assign sensitivity labels from GitHub. The scripts use a mixture of Microsoft Graph PowerShell SDK cmdlets and regular Graph requests run using the Invoke-MgGraphRequest cmdlet.

Applying Sensitivity Labels to Documents

What’s different is when the time comes to apply a sensitivity label to an unlabeled file. The assignSensitivityLabel API is straightforward. You need to know:

  • The identifier for the drive (document library) storing the target file.
  • The identifier for the target file.
  • The identifier for the sensitivity label to assign to the target file.
  • A request body (payload) for the POST request. The only mandatory item in the payload is the identifier for the sensitivity label. You can also pass a justification and an assignment method.

The request body is passed as a hash table. Here’s an example:

$AssignmentPayload = @{}
$AssignmentPayload.Add("AssignmentMethod", "Auto")
$AssignmentPayload.Add("Justification", "Trying out the assignSensivityLabel API")
$AssignmentPayload.Add("SensitivityLabelId", "27451a5b-5823-4853-bcd4-2204d03ab477")

With everything in place, posting the request to the API is a matter of doing something like this:

Write-Host ("Assigning sensitivity label to {0}" -f $File.Name)
$Uri = ("https://graph.microsoft.com/v1.0/drives/{0}/items/{1}/assignSensitivityLabel" -f $Drive.Id, $File.Id)
Try {
    Invoke-MgGraphRequest -Method "POST" -Uri $Uri -Body $AssignmentPayload -OutputType PSObject
    }
Catch {
    Write-Host ("Failed to assign sensitivity label to file {0}" -f $File.Name ) -ForegroundColor Red
}

The URI used for the request will look something like this after inserting the values for the drive and file identifiers:

https://graph.microsoft.com/v1.0/drives/b!VjyyeCWK3EGr4WX2V2zF5eWwPtRGxu9AgzwoRtLDUpDOiuY22Vv_SJt-wwtCTPyp/items/0142U6OAA3Z4BZZNZEDFHZ36VBP6I2ZQ2G/assignSensitivityLabel

If everything goes right, SharePoint Online accepts the request to label the file and the label will show up in Office UIs, SharePoint views, and so on.

Some Points about Assigning Sensitivity Labels

It’s nice to have the ability to assign sensitivity labels to Office documents and PDF files programmatically. However, you do need to take some points into consideration, including:

  • Automatically assigned sensitivity labels (for instance, using an auto-label policy) do not take precedence over labels assigned manually. For this reason, the script ignores files that already have a label. If you wanted, you could check the assignment method in the label information returned by the extractSensitivityLabels API for a document and update the sensitivity label if the label being applied has a higher priority than the existing label and the assignment label is “auto” (applied by an auto-label policy).
  • Only modern formats of Office documents and PDF files support sensitivity labels. Scripts should ignore other file types.
  • Sensitivity labels that use Double-Key encryption cannot be read by the extractSensitivityLabels API.
  • The assignSensitivityLabel API runs in the background so the update of the file with a sensitivity happens asynchronously. The API queues a job that waits until the target file is locked or available for update and then applies the sensitivity label. The update should be visible within ten minutes of running the request, but I’ve seen updates take longer to complete.

One issue I noticed is that if you attempt to update the sensitivity label for a document that is still being processed by SharePoint Online (for instance, to update encryption due to a previous label change), the update applied by the API appears to succeed but nothing happens.

I also observed that many internal server errors occur when attempting to read sensitivity label information from PDFs. The script therefore ignores errors of this nature when handling PDFs.

Costs

Each successful use of the assignSensitivityLabel API costs U.S. $0.00185 (see metered API list). Figure 2 shows the costs incurred while testing the script to apply labels (seemingly to about 75 files). You can see that the cost is assigned to the name of the resource created in Azure.

Costs for using the assignSensitivityLabel API.
Figure 2: Costs for using the assignSensitivityLabel API

Unless you plan to assign labels to tens of thousands of files, the cost won’t be very high. This metered API doesn’t rack up charges like those incurred for translating SharePoint Online documents.

Not a Replacement for Auto-Label Policies

The assignSensitivityLabel API is not a substitute for auto-label policies. These policies are designed to process large quantities of SharePoint Online documents across a tenant by identifying target files using criteria like sensitive information types or trainable classifiers. The API exists to deal with situations like labeling a small number of documents in selected sites. If you want to incorporate smarts like automatic identification of target documents, you’ll need to develop code to find and identify documents to label.

You might never need to assign sensitivity labels programmatically, but it’s nice to know that it’s possible if the necessity arises.

About the Author

Tony Redmond

Tony Redmond has written thousands of articles about Microsoft technology since 1996. He is the lead author for the Office 365 for IT Pros eBook, the only book covering Office 365 that is updated monthly to keep pace with change in the cloud. Apart from contributing to Practical365.com, Tony also writes at Office365itpros.com to support the development of the eBook. He has been a Microsoft MVP since 2004.

Comments

  1. Ophir

    The Real Person!

    Author Ophir acts as a real person and passed all tests against spambots. Anti-Spam by CleanTalk.

    Yes, through the Office365 Portal.

  2. Ophir

    The Real Person!

    Author Ophir acts as a real person and passed all tests against spambots. Anti-Spam by CleanTalk.

    Yes, I’m able to label them just normal via the Office365 editor.

  3. Ophir

    The Real Person!

    Author Ophir acts as a real person and passed all tests against spambots. Anti-Spam by CleanTalk.

    Hi Tony, great post!

    I’ve run into an issue with the assignSensitivityLabel API. I’m getting this error:
    {
    “error”: {
    “code”: “notSupported”,
    “message”: “Sensitivity label cannot be assigned due to unsupported feature.”,
    “innerError”: {
    “code”: “unprocessableEntity”
    }
    }
    }
    Any idea what might be causing this? Have you seen it before?

    Thanks!

      1. Ophir

        The Real Person!

        Author Ophir acts as a real person and passed all tests against spambots. Anti-Spam by CleanTalk.

        Standard docx files…
        Thanks for the response 🙂

Leave a Reply