Less known Graph API endpoints you can use to ensure compliance with CIS benchmark

As I was going over the latest CIS guidelines for securing your Microsoft 365 estate, I noticed that some of the controls are marked as “manual”, even though programmatic methods to collect/remediate them do exists. Now I’m definitely no expert on the benchmark and I am not familiar with the methodology used to generate it, so I am not voicing any criticism on it. I simply wanted to publish some guidance for people that might be interested in automating some of those “manual” controls. Let’s dig into it.

Idle session timeout

Reporting on and configuring Idle session timeout for Microsoft 365 apps is possible via the activityBasedTimeoutPolicy Graph API resource. Here are some examples on how to do that:

#Use direct request
GET https://graph.microsoft.com/v1.0/policies/activityBasedTimeoutPolicies

#Use the Graph SDK
Connect-MgGraph -Scopes Policy.Read.All
Get-MgPolicyActivityBasedTimeoutPolicy | fl

AppliesTo :
Definition : {{"ActivityBasedTimeoutPolicy":{"Version":1,"ApplicationPolicies":[{"ApplicationId":"default","WebSessionIdleTimeout":"06:00:00"}]}}}
DeletedDateTime :
Description :
DisplayName : ActivityBasedTimeoutPolicy
Id : c1a12545-9935-4ee1-b8bf-6e7bbefedf33
IsOrganizationDefault : True
AdditionalProperties : {}

As the idle timeout policy has some limitations (see the official documentation), it is recommended to supplement it with a Conditional access policy that has the “” control configured or ideally, sign-in frequency. We will touch on CA policies later on.

User owned apps and services

Found under the Microsoft 365 Admin Center, two settings are of note in this category: Let users access the Office store and Let users start trials on behalf of your organization. Programmatic access to said settings is available thanks to the adminAppsAndServices Graph API (beta) resource.

#Use direct request
GET https://graph.microsoft.com/beta/admin/appsAndServices

#Use the Graph SDK
Connect-MgGraph -Scopes OrgSettings-AppsAndServices.Read.All -NoWelcome
Invoke-MgGraphRequest -Uri "https://graph.microsoft.com/beta/admin/appsAndServices"

Name Value
---- -----
@odata.context https://graph.microsoft.com/beta/$metadata#admin/appsAndServices/$entity
settings {[isOfficeStoreEnabled, True], [isAppAndServicesTrialEnabled, True]}

Microsoft Forms

Similar to the above, the Graph API also exposes the adminForms resource, which allows us to query and set (some of) the settings found under Microsoft Forms category. In particular, the guidance is around the Add internal phishing protection (isInOrgFormsPhishingScanEnabled) setting, but you might as well consider leveraging some of the external sharing related settings exposed via said resource (isExternal*).


#Use direct request
GET https://graph.microsoft.com/beta/admin/forms

#Use the Graph SDK
Connect-MgGraph -Scopes OrgSettings-Forms.Read.All -NoWelcome
Invoke-MgGraphRequest -Uri "https://graph.microsoft.com/beta/admin/Forms/settings" | ft -AutoSize

Name Value
---- -----
isExternalShareCollaborationEnabled True
isBingImageSearchEnabled False
isExternalShareTemplateEnabled True
isExternalShareResultEnabled True
isInOrgFormsPhishingScanEnabled True
isExternalSendFormEnabled True
@odata.context https://graph.microsoft.com/beta/$metadata#admin/forms/settings
isRecordIdentityByDefaultEnabled True

Microsoft 365 on the web

Under this category, you can find the Let users open files stored in third-party storage services in Microsoft 365 on the web setting. Controlling this one takes a different approach, namely disabling the Office Online Third Party Storage service principal (with appID value of c1f33bc0-bdb4-4248-ba9b-096807ddb43e).

#Get the SP via the Graph API
GET https://graph.microsoft.com/v1.0/servicePrincipals?$filter=appId eq %27c1f33bc0-bdb4-4248-ba9b-096807ddb43e%27

#Use the Graph SDK to get the SP and block it
$SP = Get-MgServicePrincipal -Filter "appId eq 'c1f33bc0-bdb4-4248-ba9b-096807ddb43e'"
Update-MgServicePrincipal -ServicePrincipalId $SP.Id -AccountEnabled:$false

Do note that the SP might not exist in the tenant, in which case you will need to create it first! Credit for this solution goes to the good folks over at the Microsoft 365 DSC initiative.

Priority account protection

This one is found under the Security center > Settings. To control it, we can use Exchange Online PowerShell (no Graph API equivalent!) and the set of *-EmailTenantSettings cmdlets:

#Check whether the setting is enabled
Get-EmailTenantSettings | select EnablePriorityAccountProtection


#Configure the setting
Set-EmailTenantSettings -EnablePriorityAccountProtection $true

Per-user MFA

As the MSOnline PowerShell module is now deprecated, we need an alternative method to report on and configure the per-user MFA controls. Luckily, Microsoft just released such, via the /authentication/requirements Graph API (beta) endpoint! The documentation is a bit flaky now, but thanks to Daniel’s post, we know the permissions required for these operations are Policy.Read.All and Policy.ReadWrite.AuthenticationMethod, respectively. So here are some examples on how to report on or toggle per-user MFA:

GET https://graph.microsoft.com/beta/users/user@domain.com/authentication/requirements


PATCH https://graph.microsoft.com/beta/users/user@domain.com/authentication/requirements
    "perUserMfaState": "enabled"


Despite what Microsoft’s sales and marketing teams want you to believe, per-user MFA remains viable (and free!) option, so you might as well take advantage of it, even it goes against the recommendations. One can even argue that it represents a better option than Security defaults, as you can actually exert some control over it, instead of the “all or nothing approach”.

Microsoft Authenticator configuration

This control instructs us to configure some settings on the Microsoft Authenticator Authentication Method Policy, which will help prevent MFA fatigue. While the settings can be configured manually via the Entra Admin Center, there is also a Graph API endpoint we can leverage, namely /authenticationMethodConfigurations/microsoftAuthenticator (found under the /policies/authenticationMethodsPolicy node). The settings in question are part of microsoftAuthenticatorFeatureSettings resource, and we can report on them or configure them as follows:

#Use direct request
GET https://graph.microsoft.com/v1.0/policies/authenticationMethodsPolicy/authenticationMethodConfigurations/microsoftAuthenticator

#Use the Graph SDK for PowerShell

(Get-MgPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration -AuthenticationMethodConfigurationId microsoftAuthenticator | select -ExpandProperty AdditionalProperties).featureSettings

Key Value
--- -----
displayAppInformationRequiredState {[state, disabled]...
displayLocationInformationRequiredState {[state, enabled]...


Only two of the available properties are shown above, the rest will be visible if you use the /beta endpoint instead. As the Require number matching for push notifications (numberMatchingRequiredState) setting is now on by default, you can ignore it. The Microsoft Authenticator on companion applications setting does not fall into the scope of the benchmark. The Show application name in push and passwordless notifications (displayAppInformationRequiredState) and Show geographic location in push and passwordless notifications (displayLocationInformationRequiredState) properties are the ones to check and configure.

As PATCH-ing the policy requires you to provide its full object as JSON, I’ll leave out the example here.

Additional resources

Because I’m getting bored already, here are some additional resources that can help you with some more of the controls.

  • Everything under section 5.2.2 can be automated via the Graph API endpoints for Conditional access policies
  • The admin consent settings can be managed via the Admin consent policy resource
  • Password protection and Group-related settings can be managed via directory settings
  • Some additional controls can be taken care of by using (unsupported) calls to the https://main.iam.ad.ext.azure.com/api endpoint
  • Most of the compliance-related controls can be addressed via cmdlets from the SCC PowerShell module

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.