node.jsazurepowerbiembedbearer-token

Unauthorized to retrieve PowerBI embed token


I already have found other similar issues on Stack Overflow, but still have issue to retrieving the embed token in Node.js, with the message:

2025-03-07T08:31:35.098660921Z Error: Failed to get embed token: 401 Unauthorized -
2025-03-07T08:31:35.098716024Z     at /app/src/services/PowerBIService.ts:135:13
2025-03-07T08:31:35.098722924Z     at Generator.next (<anonymous>)
2025-03-07T08:31:35.098728225Z     at fulfilled (/app/src/services/PowerBIService.ts:5:58)
2025-03-07T08:31:35.098733225Z     at processTicksAndRejections (node:internal/process/task_queues:95:5)

I already:

The method I Created is this, I use ClientSecretCredentials with the Tenant ID, Client ID and Client Secret of the app:

async function getPowerBIEmbedResponse(
  reportId: string,
  datasetId: string,
  groupId: string
): Promise<any> {
  Logger.info("Inside getPowerBIEmbedResponse");

  try {
    const credential = new ClientSecretCredential(
      "bbbb", // Tenant ID
      "aaaa", // App Registration client ID
      "abcd" // Client secret
    );

    const tokenResponse = await credential.getToken(
      "https://analysis.windows.net/powerbi/api/.default"
    );

    // const tokenResponse = await credential.getToken(
    //   "https://graph.microsoft.com/.default"
    // );

    if (!tokenResponse || !tokenResponse.token) {
      throw new Error("Failed to retrieve Azure access token.");
    }

    Logger.info("Token obtained successfully");
    const accessToken = tokenResponse.token;

    const url = `https://api.powerbi.com/v1.0/myorg/groups/${groupId}/reports/${reportId}/GenerateToken`;
    // https://api.powerbi.com/v1.0/myorg/GenerateToken

    const response = await fetch(url, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${accessToken}`,
      },
      body: JSON.stringify({
        accessLevel: "View",
        datasetId: datasetId,
      }),
    });

    if (!response.ok) {
      const errorText = await response.text();
      Logger.error(`Error response body: ${errorText}`);
      throw new Error(
        `Failed to get embed token: ${response.status} ${response.statusText} - ${errorText}`
      );
    }

    const data = await response.json();
    return data;
  } catch (error) {
    Logger.error(`Exception in getPowerBIEmbedResponse: ${error.message}`);
    throw error;
  }

Of course I send the reportID, datasetID and groupID of the report I want to obtain the embedToken. Why I still have the issue? I tried to get the Bearer token with both the url you can see in the code (one is commented), but still. I suppose there is another way to obtain the Bearer token used to retrieve the Embed Token


Solution

  • Fixed and tested using Postman. Executing this POST API:

    https://api.powerbi.com/v1.0/myorg/groups/[groupID]/reports/[reportID]/GenerateToken
    

    with body:

    {
      "accessLevel": "View",
      "identities": [
        {
          "username": "username",
          "roles": []
        }
      ],
      "datasets": [
        {
          "id": "[datasetID]"
        }
      ]
    }
    

    I had 2 issues:

    {
        "error": {
            "code": "InvalidRequest",
            "message": "Creating embed token with effective identity requires dataset to be provided"
        }
    }
    

    and this was related to the body I sent. Effective Identity was not supported for the dataset chosen, it is used only for Row Level Security (RLS), meaning that I had to remove it and keep this body:

    {
      "accessLevel": "View",
      "datasets": [
        {
          "id": "[datasetID]"
        }
      ]
    }