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

Earn the coveted Fabric Analytics Engineer certification. 100% off your exam for a limited time only!

Reply
shaw
Frequent Visitor

400 Bad Request Error when embedding report

I am trying to embed the Power BI report into 3rd party web app. Trying to test this in Java Code Sample. I am able to authenticate, and in fact, get the response with the correct reportId, groupId. 

When I call the API https:// api.powerbi.com/v1.0/myorg/GenerateToken, it goes to catch and throws out Error: 400 Bad Request. 

I tried the same thing on postman too, likewise, I am getting the embedded URL too, please see the response below.

 

{
"@odata.context": "http://wabi-us-north-central-redirect.analysis.windows.net/v1.0/myorg/groups/xxxxxxxxxxxxxxxxxxxxxxx...",
"id": "xxxxxxxxxxxxxxxxxxxxx",
"reportType": "PowerBIReport",
"name": "My Embed Dashboard",
"webUrl": "https://app.powerbi.com/groups/xxxxxxxxxxxxxxxxxxxxx/reports/xxxxxxxxxxxxxxxxxxxx",
"embedUrl": "https://app.powerbi.com/reportEmbed?reportId=xxxxxxxxxxxxx&groupId=xxxxxxxxx=2&config=xxxxxxxx",
"isFromPbix": true,
"isOwnedByMe": true,
"datasetId": "xxxxxxxxxx"
}

 

if I access the embedUrl through the browser, I end with 400 bad request error as I get from the code debugging. 

I tried the solution proposed in this discussion, tried this on code as well as on the postman. But no luck with that. Still, the embedUrl loads nothing with the browser's console error:

DevTools failed to load SourceMap: Could not load content for https://app.powerbi.com/13.0.13035.244/scripts/interact.min.js.map: HTTP error: status code 404, net::ERR_HTTP_RESPONSE_CODE_FAILURE


SOME INFO TO TROUBLESHOOT THIS ISSUE:

Auth Method: Service Principal
Azure App Type: Web

Is Service Principal added to the security group and security group under the admin tenant settings on powerbi service : Yes

Is Service Principal added to the workspace: Yes

Is API permission provided: delegated full access to all datasets, tenant, groups, reports, workspace, capacity etc., 

Is Scope defined: consent is added for "admins and users"

Authorized client applications: Added the clientid 

 

Any help is appreciated. 


Thanks

Shawkath 

 

1 ACCEPTED SOLUTION

Hi @shaw 

If you are using the 'App owns data' type of embedding + using the Service Principal to generate embedding tokens, then this Identity section of the token request should contain details of the 'user' used for Row Level Security purposes.

Are you reports/dashboards using Row Level Security?
If so... your identity section should look like this...

"identities": [
    {
      "username": "my-user@can-be-any-value-here.com",
      "roles": [
        "My PBI Role Name"
      ],
      "datasets": [
        "cfafbeb1-8037-4d0c-896e-a46fb27ff229"
      ]
    }
  ]

 

Username can be any value - you are effectively impersonating this person - and this has no link to any account in your Azure tenant or Power BI access list.

Roles should contain any Power BI (RLS) roles that you have defined inside your data model. Note that you should not supply roles here if you are not using RLS - and dont supply roles that dont exist in your model. Again, this is not a role that belongs to your Service Principal account or any other Power BI account type (admin/member/viewer) etc..

Hope this helps,
Cheers - Matt

View solution in original post

8 REPLIES 8
OBMBI
Frequent Visitor

If anyone is having an issue wih this, I found that submitting the JSON body in the 'Try it' section in the docs gave a much better error than the generic '400 Bad Request' error.

 

https://learn.microsoft.com/en-us/rest/api/power-bi/embed-token/generate-token#code-try-0

shaw
Frequent Visitor

UPDATE: While testing the APIs, we identified the error "dataset or the user does not exist, set identify to the dataset". 

After inserting the identities node to the requestHeader (as per the JSON below)

 

 

{
  "datasets": [
    {
      "id": "cfafbeb1-8037-4d0c-896e-a46fb27ff229"
    }
  ],
  "reports": [
    {
      "id": "b2e49b01-2356-4456-bfb9-3f4c2bc4ddbd"
    }
  ],
  "identities": [
    {
      "username": "<AZURE APP ID GOES HERE>",
      "roles": [
        "Admin"
      ],
      "datasets": [
        "cfafbeb1-8037-4d0c-896e-a46fb27ff229"
      ]
    }
  ]
}

 

 


The original issue I posted here is now resolved. So we are able to see the dashboard displayed on our web application. 

Another issue still exists: Although the service principal is an admin and as an admin, this service principal has the full access to the workspace, the data is not loading on the embedded report. Only the report's layout is loading but not the actual dashboard. 

So we tried to add identities for the report level with the role name to the above-mentioned JSON. Still, we haven't got any luck so far. I also checked to have the following permissions set on the azure app. 

 

Hi @shaw 

If you are using the 'App owns data' type of embedding + using the Service Principal to generate embedding tokens, then this Identity section of the token request should contain details of the 'user' used for Row Level Security purposes.

Are you reports/dashboards using Row Level Security?
If so... your identity section should look like this...

"identities": [
    {
      "username": "my-user@can-be-any-value-here.com",
      "roles": [
        "My PBI Role Name"
      ],
      "datasets": [
        "cfafbeb1-8037-4d0c-896e-a46fb27ff229"
      ]
    }
  ]

 

Username can be any value - you are effectively impersonating this person - and this has no link to any account in your Azure tenant or Power BI access list.

Roles should contain any Power BI (RLS) roles that you have defined inside your data model. Note that you should not supply roles here if you are not using RLS - and dont supply roles that dont exist in your model. Again, this is not a role that belongs to your Service Principal account or any other Power BI account type (admin/member/viewer) etc..

Hope this helps,
Cheers - Matt

Thanks .. I was using RLS and this post helped solve the issue while moving to service principle.  username/pass seems to work fine with RLS enabled on a report even if you don't send the roles/username in the JSON, where as service principle requires it.

Hi @MattCalderwood 

 

Appreciate your help here. 

 

I tried to pass on the JSON to the request header as you suggested with the role I am using. My scenario is that the user from a school would login, based on their schoolid I am performing RLS. Role I have set is 'school' which I have mentioned correctly. I am not sure how to pass on the rule. I couldn't find any help on the community or through the official reference. 

From the UI, once the user authenticates in our web app, we will pass on the schoolid to the ajax call. 

 

{
  "datasets": [
    {
      "id": "18727ad-680b-4248-b571-xxxxxxxxxxxx"
    }
  ],
  "reports": [
    {
      "id": "xxxxxx7-31e9-4a28-8317-047df26b908c"
    }
  ],
  "identities": [
    {
      "username": "email@mycompany.com",
      "roles": [
        "school"
      ],
      "datasets": [
        "18727ad-680b-4248-b571-xxxxxxxxxxxx"
      ]
    }
  ]
}

 My assumption is that I will be passing the rule through the report.setFilter() from the AJAX call through the javascript. 

However, on both the Java & Javascript end, what would go in the perfect scenario? 

Hi @shaw 

It is worth considering the differences in behaviours between roles in Row Level Security - and report level filters.

It sounds as though something like 'School ID' would ensure that a user can only see data belonging to that particular school?
If that is the case... then Row Level Security is probably the thing to use!

The username field in the identities object in the token generation request - could be the users School ID (if you don't need to reference the email address or other identifier in your RLS roles).

Generating this token should then be done server side where the details cannot be tampered with.
The downside of simply passing through something like 'School ID' into a report level filter, is that this is done in JavaScript and can be easily manipulated.

Another aspect of report level filters is that it is possible to write Power BI measures in your data model that escape/break-out of this filter context. This can result in measures (say a count of students) being performed across ALL schools - when you were perhaps intending on limiting it to ONLY the school ID that the user has access to.
Row Level Security roles work differently to this... so once set, measures cannot retrieve data outside of the scope of that security rule.

It is tricky to build up a picture of your requirements without seeing a full data model... but I hope some of this makes sense / is useful.

Hi @MattCalderwood 

 

Imagine, I have a 'School ID' set as a role (Power BI role) as an RLS field. How do I pass on the 'School ID' to the Ajax call from the alien application? 

Javascript (Ajax Call with School ID) > Alien application's Java code in order to embed the Power BI report? 

Technically saying: 

I would like to pass on the "school ID" that I got as a global variable in the alien application readily available to pass on. I couldn't figure out how it is done on the https://microsoft.github.io/PowerBI-JavaScript/demo/v2-demo/index.html# . 

my School ID is a column from the table called "SchooldDetails"

report. <I pass on the constructed table and column info to this object? >

 $.ajax({
		        type: "GET",
		        url: "/appownsdatasample/getembedinfo",
		        dataType: "json",
		        success: function (embedData) {
		        	
		            reportLoadConfig["accessToken"] = embedData["embedToken"];
		            reportLoadConfig["embedUrl"] = embedData["embedUrl"];
		            
			        // Use the token expiry to regenerate Embed token for seamless end user experience
		            // Refer https://aka.ms/RefreshEmbedToken
		            tokenExpiry = embedData["tokenExpiry"]
		            
		            // Embed Power BI report when Access token and Embed URL are available
		            report = powerbi.embed(reportContainer, reportLoadConfig);
                
                	// Triggers when a report schema is successfully loaded
		            report.on("loaded", function () {
		                console.log("Report load successful");
		            });
		         	
			        // Triggers when a report is successfully embedded in UI
		            report.on("rendered", function () {
		                console.log("Report render successful");
                	});

 

Hi @shaw 

Apologies for the lack of response, the last few weeks have been difficult to say the least.

Are you still having issues with RLS and getting your ID's to the right place?
Happy to continue the discussion if you are stuck.

Helpful resources

Announcements
April AMA free

Microsoft Fabric AMA Livestream

Join us Tuesday, April 09, 9:00 – 10:00 AM PST for a live, expert-led Q&A session on all things Microsoft Fabric!

March Fabric Community Update

Fabric Community Update - March 2024

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