Skip to main content
cancel
Showing results for 
Search instead for 
Did you mean: 

Register now to learn Fabric in free live sessions led by the best Microsoft experts. From Apr 16 to May 9, in English and Spanish.

Reply
Anonymous
Not applicable

Can't use any Power BI APIs, get 403 even with token

I'm trying to test the APIs (get a list of datasets in my workspace) before progressing on to doing some dataflow work, but anything I do with the APIs after getting my token returns a 403 error.

 

I'm using the example website sample code from the adal python github page (https://github.com/AzureAD/azure-activedirectory-library-for-python/tree/dev/sample)

 

I added an extra requests.get call hitting up https://api.powerbi.com/v1.0/myorg/datasets to get a list of datasets and then just printing it out to the console, which gives me: 

Running API
API Result: 403

 

The resource in the parameters.json file passed into the python script is "00000009-0000-0000-c000-000000000000" which I believe is correct. When I run the token through jwt.io to check it out, I see my username and scps of:

Capacity.Read.All Capacity.ReadWrite.All Content.Create Dashboard.Read.All Dashboard.ReadWrite.All Dataflow.Read.All Dataflow.ReadWrite.All Dataset.ReadWrite.All Group.Read Report.ReadWrite.All Workspace.Read.All Workspace.ReadWrite.All

 

Any help would be appreciated.

 

try:
    from http import server as httpserver
    from http import cookies as Cookie
except ImportError:
    import SimpleHTTPServer as httpserver
    import Cookie as Cookie

try:
    import socketserver
except ImportError:
    import SocketServer as socketserver

try:
    from urllib.parse import urlparse, parse_qs
except ImportError:
    from urlparse import urlparse, parse_qs

import json
import os
import random
import string
import sys
import requests
import urllib.request

import adal

# You can provide account information by using a JSON file. Either
# through a command line argument, 'python sample.py parameters.json', or
# specifying in an environment variable of ADAL_SAMPLE_PARAMETERS_FILE.
#
# The information inside such file can be obtained via app registration.
# See https://github.com/AzureAD/azure-activedirectory-library-for-python/wiki/Register-your-application-with-Azure-Active-Directory
#
# {
#    "resource": "your_resource",
#    "tenant" : "rrandallaad1.onmicrosoft.com",
#    "authorityHostUrl" : "https://login.microsoftonline.com",
#    "clientId" : "624ac9bd-4c1c-4687-aec8-b56a8991cfb3",
#    "clientSecret" : "verySecret=""
# }

parameters_file = (sys.argv[1] if len(sys.argv) == 2 else
                   os.environ.get('ADAL_SAMPLE_PARAMETERS_FILE'))

if parameters_file:
    with open(parameters_file, 'r') as f:
        parameters = f.read()
    sample_parameters = json.loads(parameters)
else:
    raise ValueError('Please provide parameter file with account information.')

PORT = 8088
TEMPLATE_AUTHZ_URL = ('https://login.windows.net/{}/oauth2/authorize?'+
                      'response_type=code&client_id={}&redirect_uri={}&'+
                      'state={}&resource={}')
PBI_RESOURCE = '00000009-0000-0000-c000-000000000000'
RESOURCE = sample_parameters.get('resource', PBI_RESOURCE)
REDIRECT_URI = 'http://localhost:{}/getAToken'.format(PORT)

authority_url = (sample_parameters['authorityHostUrl'] + '/' +
                 sample_parameters['tenant'])

class OAuth2RequestHandler(httpserver.SimpleHTTPRequestHandler):
    def do_GET(self):
        if self.path == '/':
            self.send_response(307)
            login_url = 'http://localhost:{}/login'.format(PORT)
            self.send_header('Location', login_url)
            self.end_headers()
        elif self.path == '/login':
            auth_state = (''.join(random.SystemRandom()
                                  .choice(string.ascii_uppercase + string.digits)
                                  for _ in range(48)))
            cookie = Cookie.SimpleCookie()
            cookie['auth_state'] = auth_state
            authorization_url = TEMPLATE_AUTHZ_URL.format(
                sample_parameters['tenant'],
                sample_parameters['clientId'],
                REDIRECT_URI,
                auth_state,
                RESOURCE)
            self.send_response(307)
            self.send_header('Set-Cookie', cookie.output(header=''))
            self.send_header('Location', authorization_url)
            self.end_headers()
        elif self.path.startswith('/getAToken'):
            is_ok = True
            try:
                token_response = self._acquire_token()
                access_token = token_response['accessToken']
                #Later, if the access token is expired it can be refreshed.
                #auth_context = adal.AuthenticationContext(authority_url)
                #token_response_refresh = auth_context.acquire_token_with_refresh_token(
                #    token_response['refreshToken'],
                #    sample_parameters['clientId'],
                #    RESOURCE,
                #    sample_parameters['clientSecret'])
                ################OK We now have a token, lets do stuff with it to see if that works#########################
                #refresh_token = token_response_refresh['accessToken']
                print("Running API")
                headers = {'Authorization': 'Bearer {}'.format(access_token), 'Content-Type': 'application/json'}
                api = requests.get('https://api.powerbi.com/v1.0/myorg/datasets', headers=headers)
                print("API Result: {}\n{}\n".format(api.status_code, api.text))
                message = "Full Token Response: {}<br><br>token: {}<br><br>Status Code: {}<br>Returned: {}".format(token_response, access_token, api.status_code, api.text)
            except ValueError as exp:
                message = str(exp)
                is_ok = False
            self._send_response(message, is_ok)

    def _acquire_token(self):
        parsed = urlparse(self.path)
        code = parse_qs(parsed.query)['code'][0]
        state = parse_qs(parsed.query)['state'][0]
        cookie = Cookie.SimpleCookie(self.headers["Cookie"])
        if state != cookie['auth_state'].value:
            raise ValueError('state does not match')
        ### Main logic begins
        auth_context = adal.AuthenticationContext(authority_url)
        return auth_context.acquire_token_with_authorization_code(
            code,
            REDIRECT_URI,
            RESOURCE,
            sample_parameters['clientId'],
            sample_parameters['clientSecret'])
        ### Main logic ends

    def _send_response(self, message, is_ok=True):
        self.send_response(200 if is_ok else 400)
        self.send_header('Content-type', 'text/html')
        self.end_headers()

        if is_ok:
            #todo, pretty format token response in json
            message_template = ('<html><head><title>Succeeded</title></head>'
                                '<body><p>{}</p></body></html>')
        else:
            message_template = ('<html><head><title>Failed</title></head>'
                                '<body><p>{}</p></body></html>')

        output = message_template.format(message)
        self.wfile.write(output.encode())

httpd = socketserver.TCPServer(('', PORT), OAuth2RequestHandler)

print('serving at port', PORT)
httpd.serve_forever()
1 ACCEPTED SOLUTION
Anonymous
Not applicable

Finally figured it out. The resource in the parameters.json needs to be https://analysis.windows.net/powerbi/api or it won't work.

View solution in original post

1 REPLY 1
Anonymous
Not applicable

Finally figured it out. The resource in the parameters.json needs to be https://analysis.windows.net/powerbi/api or it won't work.

Helpful resources

Announcements
Microsoft Fabric Learn Together

Microsoft Fabric Learn Together

Covering the world! 9:00-10:30 AM Sydney, 4:00-5:30 PM CET (Paris/Berlin), 7:00-8:30 PM Mexico City

PBI_APRIL_CAROUSEL1

Power BI Monthly Update - April 2024

Check out the April 2024 Power BI update to learn about new features.

April Fabric Community Update

Fabric Community Update - April 2024

Find out what's new and trending in the Fabric Community.