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

Don't miss out! 2025 Microsoft Fabric Community Conference, March 31 - April 2, Las Vegas, Nevada. Use code MSCUST for a $150 discount. Prices go up February 11th. Register now.

Reply
calm1kov
Regular Visitor

Generating report embed token return 401

Hi,

 

Following this tutorial and  Embedding with non-Power BI users, I already successfully embeded dashboard for non-Power BI users.

 

I've used the approach of retrieving access token for master account (pro) with username and password.

Then generating embed token with access token.

 

I have to say that there is lack of API documentation for non C# developers.

Also when there is error - no error code given or explanation. Not developer friendly at all.

 

Below is simple examle of embeding Dashboard with PHP:

Spoiler
<?php

$ch_access_token = curl_init();

$oauth_data = [
    'grant_type' => 'password',
    'username' => 'master-usern@domain.onmicrosoft.com',
    'password' => '123456',
    'client_id' => 'x7957710-04xc-1a345-1234-097d273f4az2',
    'resource' => 'https://analysis.windows.net/powerbi/api',
];

curl_setopt($ch_access_token, CURLOPT_URL, 'https://login.microsoftonline.com/common/oauth2/token');
curl_setopt($ch_access_token, CURLOPT_POST, 1);
curl_setopt($ch_access_token, CURLOPT_POSTFIELDS, http_build_query($oauth_data));

// receive server response ...
curl_setopt($ch_access_token, CURLOPT_RETURNTRANSFER, true);

$server_output_access_token = curl_exec($ch_access_token);

curl_close($ch_access_token);

$token_data = json_decode($server_output_access_token, true);

$access_token = $token_data['access_token'] ?? '';

if (!$access_token) {
    die('NA');
}

$ch_entity_token = curl_init();

$json_body = [
    'accessLevel' => 'View'
];

$group_id = 'ad567a8z-088x-1234-3456-112255a2a5a2';
$entity_id = 'zb567a8z-088x-1234-448-33775a2a5a2b';

curl_setopt($ch_entity_token, CURLOPT_URL,
    "https://api.powerbi.com/v1.0/myorg/groups/{$group_id}/dashboards/{$entity_id}/GenerateToken"
);
curl_setopt($ch_entity_token, CURLOPT_POST, 1);
curl_setopt($ch_entity_token, CURLOPT_HTTPHEADER, [
    'Content-Type: application/json; charset=utf-8',
    "Authorization: Bearer {$access_token}"
]);
curl_setopt($ch_entity_token, CURLOPT_POSTFIELDS, json_encode($json_body));

// receive server response ...
curl_setopt($ch_entity_token, CURLOPT_RETURNTRANSFER, true);

$server_output_dashboard_token = curl_exec($ch_entity_token);

curl_close($ch_entity_token);


$entity_token_data = json_decode($server_output_dashboard_token, true);

if (!isset($entity_token_data['token'])) {
    die('NA');
}

?>
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8"/>
    <title>Test page</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script
            src="https://code.jquery.com/jquery-3.2.1.min.js"
            integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4="
            crossorigin="anonymous"></script>

    <script src="js/powerbi.js"></script>
    <style>
        html {
            height: 100%;
        }
    </style>
</head>
<body style="height: 100%">
<div id="dashboardContainer" style="height: 100%">
</div>
<script>
    // Read embed application token from Model
    var accessToken = "<?=$entity_token_data['token']?>";

    // Read dashboard Id from Model
    var embedEntityId = "<?=$entity_id?>";

    // Read embed URL from Model
    var embedUrl = 'https://app.powerbi.com/dashboardEmbed';

    // Get models. models contains enums that can be used.
    var models = window['powerbi-client'].models;

    // Embed configuration used to describe the what and how to embed.
    // This object is used when calling powerbi.embed.
    // This also includes settings and options such as filters.
    // You can find more information at https://github.com/Microsoft/PowerBI-JavaScript/wiki/Embed-Configuration-Details.
    var config = {
        type: 'dashboard',
        tokenType: models.TokenType.Embed,
        accessToken: accessToken,
        embedUrl: embedUrl,
        id: embedEntityId
    };

    // Get a reference to the embedded dashboard HTML element
    var dashboardContainer = $('#dashboardContainer')[0];

    // Embed the dashboard and display it within the div container.
    var dashboard = powerbi.embed(dashboardContainer, config);
</script>

 

 So far so good. Dashboard embeded. True fullstack I am.

 

Lets copy-paste above code, replace dashboard with report and we will have report embeded you would say.

Well, maybe with another API's but not with microsoft lol.

 

Below is implementation of report embed:

 

Spoiler

 

<?php

$ch_access_token = curl_init();

$oauth_data = [
    'grant_type' => 'password',
    'username' => 'master-usern@domain.onmicrosoft.com',
    'password' => '123456',
    'client_id' => 'x7957710-04xc-1a345-1234-097d273f4az2',
    'resource' => 'https://analysis.windows.net/powerbi/api',
];

curl_setopt($ch_access_token, CURLOPT_URL, 'https://login.microsoftonline.com/common/oauth2/token');
curl_setopt($ch_access_token, CURLOPT_POST, 1);
curl_setopt($ch_access_token, CURLOPT_POSTFIELDS, http_build_query($oauth_data));

// receive server response ...
curl_setopt($ch_access_token, CURLOPT_RETURNTRANSFER, true);

$server_output_access_token = curl_exec($ch_access_token);

curl_close($ch_access_token);

$token_data = json_decode($server_output_access_token, true);

$access_token = $token_data['access_token'] ?? '';

if (!$access_token) {
    die('NA');
}

$ch_entity_token = curl_init();

$json_body = [
    'accessLevel' => 'View'
];

$group_id = 'ad567a8z-088x-1234-3456-112255a2a5a2';
$entity_id = 'zb567a8z-088x-1234-448-33775a2a5a2b';

curl_setopt($ch_entity_token, CURLOPT_URL,
    "https://api.powerbi.com/v1.0/myorg/groups/{$group_id}/reports/{$entity_id}/GenerateToken"
);
curl_setopt($ch_entity_token, CURLOPT_POST, 1);
curl_setopt($ch_entity_token, CURLOPT_HTTPHEADER, [
    'Content-Type: application/json; charset=utf-8',
    "Authorization: Bearer {$access_token}"
]);
curl_setopt($ch_entity_token, CURLOPT_POSTFIELDS, json_encode($json_body));

// receive server response ...
curl_setopt($ch_entity_token, CURLOPT_RETURNTRANSFER, true);

$server_output_report_token = curl_exec($ch_entity_token);

curl_close($ch_entity_token);

$entity_token_data = json_decode($server_output_report_token, true);

if (!isset($entity_token_data['token'])) {
    die('NA');
}

?>
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8"/>
    <title>Test page</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script
            src="https://code.jquery.com/jquery-3.2.1.min.js"
            integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4="
            crossorigin="anonymous"></script>

    <script src="js/powerbi.js"></script>
    <style>
        html {
            height: 100%;
        }
    </style>
</head>
<body style="height: 100%">
<div id="reportContainer" style="height: 100%">
</div>
<script>
    // Read embed application token from Model
    var accessToken = "<?=$entity_token_data['token']?>";

    // Read report Id from Model
    var embedEntityId = "<?=$entity_id?>";

    // Read embed URL from Model
    var embedUrl = 'https://app.powerbi.com/reportEmbed';

    // Get models. models contains enums that can be used.
    var models = window['powerbi-client'].models;

    // Embed configuration used to describe the what and how to embed.
    // This object is used when calling powerbi.embed.
    // This also includes settings and options such as filters.
    // You can find more information at https://github.com/Microsoft/PowerBI-JavaScript/wiki/Embed-Configuration-Details.
    var config = {
        type: 'report',
        tokenType: models.TokenType.Embed,
        accessToken: accessToken,
        embedUrl: embedUrl,
        id: embedEntityId
    };

    // Get a reference to the embedded report HTML element
    var reportContainer = $('#reportContainer')[0];

    // Embed the report and display it within the div container.
    var report = powerbi.embed(reportContainer, config);
</script>

 

 

 Generate embed token for report return 401 Unauthorized

 Howewer the response from access token has all necessary scopes:

 

Access token request's response:

{
    "token_type": "Bearer",
    "scope": "Dashboard.Read.All Dataset.Read.All Group.Read Report.ReadWrite.All",
    "expires_in": "3600",
    "ext_expires_in": "0",
    "expires_on": "1498449876",
    "not_before": "1498445976",
    "resource": "https://analysis.windows.net/powerbi/api",
    "access_token": "eyJ0eXAiO...T3DwV2XQ",
    "refresh_token": "AQABAAAAAABnfiG-...-Wzb-zqO1ExGK31EUyy8gAA"
}

Embed token request (return 401):

POST /v1.0/myorg/groups/ad567a8z-088x-1234-3456-112255a2a5a2/reports/zb567a8z-088x-1234-448-33775a2a5a2b/GenerateToken HTTP/1.1
Host: api.powerbi.com
Content-Type: application/json; charset=utf-8
Authorization: Bearer eyJ0eXAiO...T3DwV2XQ

{"accessLevel": "View", "allowSaveAs": false}

Few more details:

 

- I have pro license (trial)

 

- Report is part of group(workspace)

 

 

- Application was created through https://dev.powerbi.com/apps

 

- All permissions was set in AD

 

 

 

Any 5 cents appresiated.

Regards.

 

 

 

2 REPLIES 2
Anonymous
Not applicable

Hello 
I want to reproduce this part on C# to manage row level security with php code.
Any help ?

 

GenerateTokenRequest generateTokenRequestParameters;
                    // This is how you create embed token with effective identities
                    if (!string.IsNullOrEmpty(username))
                    {
                        var rls = new EffectiveIdentity(username, new List<string> { report.DatasetId });
                        if (!string.IsNullOrWhiteSpace(roles))
                        {
                            var rolesList = new List<string>();
                            rolesList.AddRange(roles.Split(','));
                            rls.Roles = rolesList;
                        }
                        // Generate Embed Token with effective identities.
                        generateTokenRequestParameters = new GenerateTokenRequest(accessLevel: "view", identities: new List<EffectiveIdentity> { rls });
                    }
                    else
                    {
                        // Generate Embed Token for reports without effective identities.
                        generateTokenRequestParameters = new GenerateTokenRequest(accessLevel: "view");
                    }

 

Eric_Zhang
Microsoft Employee
Microsoft Employee


@calm1kov wrote:

 

Howewer the response from access token has all necessary scopes:

 

Access token request's response:

{
    "token_type": "Bearer",
    "scope": "Dashboard.Read.All Dataset.Read.All Group.Read Report.ReadWrite.All",
    "expires_in": "3600",
    "ext_expires_in": "0",
    "expires_on": "1498449876",
    "not_before": "1498445976",
    "resource": "https://analysis.windows.net/powerbi/api",
    "access_token": "eyJ0eXAiO...T3DwV2XQ",
    "refresh_token": "AQABAAAAAABnfiG-...-Wzb-zqO1ExGK31EUyy8gAA"
}

 

 

- Application was created through https://dev.powerbi.com/apps

 

- All permissions was set in AD

 


@calm1kov

Based on my test, that scope is sufficient to request a dashboard embedtoken however not for a report embedtoken.

 

When all permissions are checked, I get the accesstoken with scope like

    "token_type": "Bearer",
    "scope": "Content.Create Dashboard.Read.All Data.Alter_Any Dataset.Read.All Dataset.ReadWrite.All Group.Read Group.Read.All Metadata.View_Any Report.Read.All Report.ReadWrite.All",

When did you check all permissions in AD?  Even though I'm not an expert on AAD, I think you have the same "re-prompt the user with the consent page" in this thread. The the permission doesn't change at all even though you already set all permission before re-consent. I'm not aware of how to re-consent, however you could follow below steps to grant all permission initially and it indeed works to request a report embedtoken base on my test.

 

1.Register a app through https://dev.powerbi.com/apps.

2.Check all permissions and save.

3.Grant permission.

Capture.PNG

4. Request accesstoken with this client_id.

 

 

 

Helpful resources

Announcements
Las Vegas 2025

Join us at the Microsoft Fabric Community Conference

March 31 - April 2, 2025, in Las Vegas, Nevada. Use code MSCUST for a $150 discount! Prices go up Feb. 11th.

Jan25PBI_Carousel

Power BI Monthly Update - January 2025

Check out the January 2025 Power BI update to learn about new features in Reporting, Modeling, and Data Connectivity.

Jan NL Carousel

Fabric Community Update - January 2025

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