Forum Discussion

JoeEdwards's avatar
JoeEdwards
Frequent Visitor
6 years ago
Solved

Get Bearer Token Via Power Query to Interrogate Power BI APIs

I would like to build a Power BI report based on data about my Power BI tenant via the Power BI APIs (unless of course there is another way to report directly on the tenant content...), and I can do this easily enough like this:

let
Token = [Authorization = "Bearer " & ManualToken],
API = Web.Contents("https://api.powerbi.com/v1.0/myorg/groups", [Headers=Token]),
ChangeResponseToRecord = Json.Document(Text.FromBinary(API)),
ConvertToTable = Table.FromList(ChangeResponseToRecord[value], Splitter.SplitByNothing(), {"Record"}, null, ExtraValues.Error),
ExpandColumn = Table.ExpandRecordColumn(ConvertToTable, "Record", {"id", "isReadOnly", "isOnDedicatedCapacity", "name"})
in
ExpandColumn

However what I cannot manage to get automatically is the "ManualToken". I can get a bearer token by going to https://docs.microsoft.com/en-us/rest/api/power-bi/groups/getgroups and clicking "Try It", and if I copy and paste that into my variable above it works fine, but I want an automated Power Query way to achieve this.

We have tried all sorts of combinations of App Registrations in Azure, and various authenication methods to get the token, and the results are:

The following successfully retrieves a bearer token:

let
BodyRecord = [grant_type = "client_credentials", resource = "<GUID Registered Application ID>", client_id = "<GUID Client Id>", client_secret = "<Client Secret>"],
Body = Uri.BuildQueryString(BodyRecord),
API = Web.Contents("https://login.microsoft.com/<Domain Name>.onmicrosoft.com/oauth2/token?api-version=1.0", [Content=Text.ToBinary(Body)]),
ChangeResponseToRecord = Json.Document(Text.FromBinary(API)),
GetAccessToken = ChangeResponseToRecord[access_token]
in
GetAccessToken

However that bearer token does not work with the Power BI APIs, even though the registered app has Microsoft Graph User.Read and all Power BI Service permissions.

The following successfully authenticates and calls the Power BI API:

# Install-Module -Name AzureRM.profile

$clientID = "<GUID Client Id>"

function GetAuthToken
{
if(-not (Get-Module AzureRm.Profile))
{
Import-Module AzureRm.Profile
}

$redirectUri = "urn:ietf:wg:oauth:2.0:oob"
$resourceAppIdURI = "https://analysis.windows.net/powerbi/api"
$authority = "https://login.microsoftonline.com/common/oauth2/authorize";
$authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList $authority
$authResult = $authContext.AcquireToken($resourceAppIdURI, $clientId, $redirectUri, "Auto")
return $authResult
}

$token = GetAuthToken
Add-Type -AssemblyName System.Net.Http

# Building Rest API header with auth token
$auth_header = @{
'Content-Type'='application/json'
'Authorization'=$token.CreateAuthorizationHeader()
}

# Get groups as example:
$uri = "https://api.powerbi.com/v1.0/myorg/groups/"
$all_groups = (Invoke-RestMethod -Uri $uri –Headers $auth_header –Method GET).value

# output to terminal
write-output $all_groups

However we can see no way to convert this into Power Query.

I am open to any suggestions!

Thanks,

Joe

  • artemus's avatar
    artemus
    6 years ago

    The only other approach I see then is to set up an Azure function which gets the auth for you.

3 Replies

  • artemus's avatar
    artemus
    Microsoft Employee

    The "easy" answer is to build your own connector which will give you access to the APIs to do this. However, you won't be able to do online refresh unless you get it certified.

    • JoeEdwards's avatar
      JoeEdwards
      Frequent Visitor

      Thanks, but ideally I would like to avoid building a custom connector, as it then has to be supported by my organisation.

      A couple of points of clarity to help: I would like to access the Power BI APIs via Power BI Service Dataflows, and also I have to use multi factor authentication in our organisation.

      Thanks,

      Joe

      • artemus's avatar
        artemus
        Microsoft Employee

        The only other approach I see then is to set up an Azure function which gets the auth for you.