Getting 403 Forbidden when connecting Defender API to Power BI

Chathurika Alahakoon 0 Reputation points
2026-08-09T16:07:02.35+00:00

I'm trying to connect Microsoft Defender data to Power BI using the Defender API & Power Query.

The Entra ID app registration & required API permissions have already been granted, & I'm able to successfully get an access token. However, when I try to call the Defender API endpoint api/deviceinfo from Power Query, I get a 403 Forbidden - Access to the resource is forbidden error.

Has anyone successfully connected this Defender API endpoint to Power BI using an Entra ID application with the client credentials flow?

Is there any additional configuration or specific permission required for this endpoint?

Microsoft 365 and Office | Development | Other
0 comments No comments

1 answer

Sort by: Most helpful
  1. Michelle Nguyen 1,180 Reputation points Independent Advisor
    2026-08-10T12:06:54.6866667+00:00

    Hi @Chathurika Alahakoon

    Based on my research, the client credentials flow can be used to connect Microsoft Defender data to Power BI. However, successfully obtaining an access token only confirms that the application was authenticated. It does not confirm that the token was issued for the correct API resource or contains the application roles required by the endpoint.

    The first thing I would verify is the exact endpoint being called.

    1. Confirm whether you need the Machines API or the DeviceInfo table

    For Microsoft Defender for Endpoint device inventory, the documented endpoint is:

    GET https://api.security.microsoft.com/api/machines

    This endpoint supports application authentication and requires one of the following WindowsDefenderATP application permissions: Machine.Read.All
    or, if write access is required: Machine.ReadWrite.All

    These permissions are exposed by the WindowsDefenderATP, also shown as Microsoft Defender for Endpoint, enterprise application. They are not Microsoft Graph permissions. Microsoft documents Machine.Read.All as the application permission for reading all machine profiles.

    A Power BI reporting implementation using an Entra ID application and Machine.Read.All has also been reported as working when the permission is added under the WindowsDefenderATP API.

    However, this endpoint is not commonly documented: GET https://api.security.microsoft.com/api/deviceinfo

    DeviceInfo is normally an Advanced Hunting table, not a standalone REST resource. If the goal is to query the DeviceInfo table, you need to run a KQL query through an Advanced Hunting endpoint rather than calling /api/deviceinfo directly.

    For example, using Microsoft Graph: POST https://graph.microsoft.com/v1.0/security/runHuntingQuery

    Request body:

    {
     "Query": "DeviceInfo | summarize arg_max(Timestamp, *) by DeviceId | take 1000"
    }
    

    For app-only authentication, this Microsoft Graph operation requires the following application permission: ThreatHunting.Read.All

    Microsoft Graph documents ThreatHunting.Read.All as the least-privileged application permission for runHuntingQuery.

    Therefore, the correct permission depends on what you are trying to retrieve:

    • For current Defender machine profiles through /api/machines, use the WindowsDefenderATP application permission Machine.Read.All.
    • For the Advanced Hunting DeviceInfo table, use Microsoft Graph ThreatHunting.Read.All and call /security/runHuntingQuery.

    Ref:

    List machines API

    security: runHuntingQuery

    2.Verify the token scope and audience

    For the Defender API, the OAuth 2.0 client credentials token request should normally use:

    scope=https://api.security.microsoft.com/.default

    For Microsoft Graph Advanced Hunting, use:

    scope=https://graph.microsoft.com/.default

    A token issued for Microsoft Graph cannot be used against api.security.microsoft.com, and a Defender token cannot be used against Microsoft Graph.

    It is possible to receive a valid token that does not contain the expected application permissions if the token was requested for the wrong resource. Similar Defender API authorization issues have been resolved by correcting the resource or scope used in the token request.

    3.Check Defender licensing, provisioning, and device availability

    Also verify that:

    • Microsoft Defender for Endpoint is provisioned for the tenant.
    • The tenant has an applicable Defender license.
    • Devices have been onboarded and are communicating with Defender.
    • Admin consent has been granted for the application permission.
    • The application is accessing the correct tenant.
    • Any Defender RBAC or device-group configuration is not limiting access.

    For the documented Machines API, Microsoft states that results are subject to Defender device-group access and that the API returns machines that have communicated with Defender for Endpoint.

    1. Power Query example for the Machines API

    If the requirement is to retrieve the Defender device inventory, the Power Query request can follow this pattern:

    let
     TenantId = "YOUR-TENANT-ID",
     ClientId = "YOUR-CLIENT-ID",
     ClientSecret = "YOUR-CLIENT-SECRET",
     TokenResponse =
     Json.Document(
     Web.Contents(
     "https://login.microsoftonline.com",
     [
     RelativePath = TenantId & "/oauth2/v2.0/token",
     Headers = [
     #"Content-Type" = "application/x-www-form-urlencoded"
     ],
     Content =
     Text.ToBinary(
     Uri.BuildQueryString(
     [
     client_id = ClientId,
     client_secret = ClientSecret,
     scope = "https://api.security.microsoft.com/.default",
     grant_type = "client_credentials"
     ]
     )
     )
     ]
     )
     ),
     AccessToken = TokenResponse[access_token],
     DefenderResponse =
     Json.Document(
     Web.Contents(
     "https://api.security.microsoft.com",
     [
     RelativePath = "api/machines",
     Headers = [
     Authorization = "Bearer " & AccessToken,
     Accept = "application/json"
     ]
     ]
     )
     ),
     Machines = DefenderResponse[value],
     Result =
     if List.Count(Machines) = 0 then
     #table({}, {})
     else
     Table.FromRecords(Machines)
    in
     Result
    

    The documented Machines API supports GET /api/machines, uses a bearer token, and supports OData operators such as $filter, $top, and $skip.

    In Power BI, because the bearer token is being supplied by Power Query, the credentials for the API data source usually need to be configured as Anonymous. The query itself will still send the Authorization: Bearer header.

    I hope this information helps.

    Was this answer helpful?


Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.