0

I am able to get a token using the default scope for powerbi ( "scope" : "https://analysis.windows.net/powerbi/api/.default"] )

With that token, I am able to read the workspaces my user has access to, ( "https://api.powerbi.com/v1.0/myorg/groups") and the reports information inside each of those workspaces ( "https://api.powerbi.com/v1.0/myorg/reports/")

But it does not matter if I reuse the same token or just acquire a brand new, if I try to export a specific report, I got a 401 error code. This is the way I am issuing the requests.get

 token_ = <new token or reused from previous get requests> 
 reports = requests.get(  # Use token to call downstream service
      config['reports']+report_id+'/Export',
      headers={'Authorization': 'Bearer ' + token_ },)

Now, if I go to https://learn.microsoft.com/en-us/rest/api/power-bi/reports/getreportsingroup
and sign in (with the same user I am using on my python script). Get the token from that page and use it on my script. It works, If I use it in postman, it works I I try to use the token acquired by my script in Postman, I also get a 401 error. So, yes, my script is not getting the correct token for this particular entry point but it is good enough for the groups and reports entry point.

Is there anything I need to add to the request for the token on this particular entry point?

Thank you very much, Andres

Here is the full script I am using, there is also a params.json that looks like this:

{
    "authority": "https://login.microsoftonline.com/1abcdefg-abcd-48b6-9b3c-bd5123456",
    "client_id": "5d2545-abcd-4765-8fbb-53555f2fa91",
    "username":"myusername@tenant",
    "password": "mypass",
    "scope" : ["https://analysis.windows.net/powerbi/api/.default"],
    "workspaces" : "https://api.powerbi.com/v1.0/myorg/groups",
    "reports": "https://api.powerbi.com/v1.0/myorg/reports/"

}


#script based on msal github library sample
import sys  # For simplicity, we'll read config file from 1st CLI param sys.argv[1]
import json
import logging
import requests
import msal

def exportReport(report_id,token_):
        result = app.acquire_token_by_username_password( config["username"], config["password"], scopes=config["scope"])
        token_ = result['access_token']
        print(f'Using token: {token_}')
        reports = requests.get(  # Use token to call downstream service
          config['reports']+report_id+'/Export',
          headers={'Authorization': 'Bearer ' + token_ },)
        print(f'-reports: {reports.status_code}')

def list_reports(workspace_id,ws_id,ws_name,token_):
    print(f'reports id for workspace {ws_name}')
    for rp in workspace_id['value']:
        if rp["id"] == "1d509119-76a1-42ce-8afd-bd3c420dd62d":
          exportReport("1d509119-76a1-42ce-8afd-bd0c420dd62d",token_)

def list_workspaces(workspaces_dict):
    for ws in workspaces_dict['value']:
        yield (ws['id'],ws['name'])

config = json.load(open('params.json'))

app = msal.PublicClientApplication(
    config["client_id"], authority=config["authority"],
    )

result = None

if not result:
    logging.info("No suitable token exists in cache. Let's get a new one from AAD.")
    result = app.acquire_token_by_username_password(
        config["username"], config["password"], scopes=config["scope"])

if "access_token" in result:
    workspaces = requests.get(  # Use token to call downstream service
        config['workspaces'],
        headers={'Authorization': 'Bearer ' + result['access_token']},).json()
    ids=list_workspaces(workspaces) #prepare workspace generator
    headers = {'Authorization': 'Bearer ' + result['access_token']}
    while True:
      try:
        ws_id,ws_name=next(ids)
        reports = requests.get(  # Use token to call downstream service
          config['workspaces']+'/'+ws_id+'/reports',
          headers={'Authorization': 'Bearer ' + result['access_token']},).json()
        list_reports(reports,ws_id,ws_name,result['access_token'])
      except StopIteration: 
        exit(0)
else:
    print(result.get("error"))
    print(result.get("error_description"))
    print(result.get("correlation_id"))  # You may need this when reporting a bug
    if 65001 in result.get("error_codes", []): 
        # AAD requires user consent for U/P flow
        print("Visit this to consent:", app.get_authorization_request_url(config["scope"]))
1
  • Please show the code you used to get the token. Commented Feb 25, 2021 at 1:23

1 Answer 1

0

From your description, I suppose you didn't grant the correct permission for your AD App used to login your user account in the code, please follow the steps below.

Navigate to the Azure portal -> Azure Active Directory -> App registrations -> find your AD App used in the code(filter with All applications) -> API permissions -> add the Report.Read.All Delegated permission in Power BI Service API(this permission is just for read action, if you need some further write operation, choose Report.ReadWrite.All) -> click the Grant admin consent for xxx button at last.

enter image description here

enter image description here

enter image description here

Update:

Use the application id of the access token got from Get-PowerBIAccessToken solve the issue.

Sign up to request clarification or add additional context in comments.

17 Comments

Thank you so much for your very descriptive answer. I am off for today, but tomorrow early in the morning I'll follow your recommendations and report back.
Good Morning Joy, I already had that permission on my app. And my user had already being granted the consent by the admin. That's how I am able to read the reports and workspaces using my script. These are my current API permissions on the app: Power BI Service: App.Read.All, CapacityReadAll, Dashboard.Read.All, Dataflow.Read.All, Dataset.Read.All, Gateway. Read.All, Report.Read.All, StorageAcount.Read.All, Tenant.Read.All, Workspace.ReadAll. They are all already granted to my user.
I edited the original post to include the script and json file I am using for authentication.
@MisterWalrus Paste your token in this page jwt.io, then see if the scp claim contains the Report.Read.All permission.
@MisterWalrus There is no such feature, updated your comment in my answer.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.