'Access to Defender for Endpoint API with delegated-context interactively in Powershell

I need to write a Powershell script that can isolate a device. This script should use delegated-permission to avoid secrets inside the script. Also, it will run interactively with user who have permissions inside Defender.

Basically, I'm trying to adapt this documentation from Microsoft (in C#) with a Powershell script: https://docs.microsoft.com/en-us/microsoft-365/security/defender-endpoint/exposed-apis-create-app-nativeapp?view=o365-worldwide

I registered an Azure App, gave appropriate API permission and would like to rely on MSAL.PS module to handle authentication with an interactive browser (we are using an external IDP). Please note that I'm starting with scope "Alert.Read" before going further :)

$resource = "https://api.securitycenter.microsoft.com"
$scope = "Alert.Read" # Delegated User Impersonation
$clientID = "<my azure app id>"
$tenantID = "<tenant id>" 
$myUPN = "<my upn>" 

$myAccessToken = Get-MsalToken -ClientId $clientID `
        -TenantId $tenantID `
        -Scopes "$($resource)/$($scope)" `
        -LoginHint $myUPN `
        -Interactive 

When I'm trying this snippet, I got the prompt, logon successfully through my IdP, then Microsoft is telling me that I should use another way to connect like using Edge. Also it gives me interesting "Error Code: 50131".

So I checked conditionnal access on Azure and disabled all policies with my account but it doesn't work.

The Azure sign-in logs for my account is reporting the following (despite i have MFA through the IdP, and nothing "applied" in the conditionnal access tab):

Authentication requirement : Single-factor authentication

Status : Failure

Continuous access evaluation : No

Sign-in error code : 50131

Failure reason : Device is not in required device state: {state}. Or, the request was blocked due to suspicious activity, access policy, or security policy decisions.

The "{state}" looks weird to me. Is this a bug somewhere? Other fact that I can't explain, when configuring the API for WindowsDefenderATP in Azure Portal, I saw an entry pointing to "https://userrequestsgraphapiep-prd.trafficmanager.net/". (I tried this in the resource URL without any success).

Is there any better way to handle this problematic? (I was thinking about an Application context for authentication with the secret in an Azure Vault, or using device login ?)

NB: The following is working with the Graph API endpoint and delegated-context

$resource = "https://graph.microsoft.com" 
$scope = "User.ReadWrite.All" 
$clientID = "<same app id>" 
$tenantID = "<my tenant>" 
$myUPN = "<my upn>" 

$myAccessToken = Get-MsalToken -ClientId $clientID `
        -TenantId $tenantID `
        -Scopes "$($resource)/$($scope)" `
        -LoginHint $myUPN `
        -Interactive
$Header = @{ Authorization = "$($myAccessToken.TokenType) $($myAccessToken.AccessToken)" }
Invoke-RestMethod -Method Patch -uri "https://graph.microsoft.com/v1.0/users/$($adUser.UserPrincipalName)"  -Headers $Header -Body '{ "accountEnabled" : "false" }' -ContentType 'application/json'

Edit: I was able to get a valid token with the following:

Import-Module MSAL.PS
$clientId = "<same app id>"
$tenantId = "<my tenant>"
$redirectUri = New-Object system.uri("https://login.microsoftonline.com/common/oauth2/nativeclient")
$authority = "https://login.microsoftonline.com/$tenantId";
$app = [Microsoft.Identity.Client.PublicClientApplicationBuilder]::Create($ClientId).WithAuthority($authority).WithRedirectUri($redirectUri).Build()
$scopes = New-Object System.Collections.ObjectModel.Collection["string"]
$scopes.Add("https://api.securitycenter.microsoft.com/Alert.Read")
#$authenticationResult = $app.AcquireTokenInteractive($scopes).WithLoginHint($upn).ExecuteAsync().Result;
$authenticationResult = $app.AcquireTokenInteractive($scopes).ExecuteAsync().Result;
$headers = @{ 
    "Authorization" = $authenticationResult.CreateAuthorizationHeader();
    "Content-Type" = "application/json";
}
Invoke-RestMethod -Method Get -URi "https://api.securitycenter.microsoft.com/api/alerts" -Headers $Headers

But I'm not prompted by my IdP (Okta) for my secondary factor... From Azure Logs, I'm using an non-interactive logon process now. But if I don't use "withLoginHint($upn)" I definitely use the integrated browser etc.



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source