microsoft / powerbi-client-angular

Power BI Angular component. This library lets you embed Power BI report, dashboard, dashboard tile, report visual, or Q&A in your Angular application.
Other
128 stars 61 forks source link

Refresh Token issue on token expiry #61

Open jaspreet1234567 opened 2 months ago

jaspreet1234567 commented 2 months ago

Hi,

I am using powerbi-client-angular to embed one of the report in angular 14 component. The access token we are providing to embedConfig had expiry time set to 1 hour. I added one method which is responsible to compare the expiration time to get the new token 10 mins before of expiry. I trying to set that token but not able to do so. I used following two ways but both not working.

  1. The first way is. Get the new token, create new instance of IReportEmbedConfiguration interface, update the access token and embed url and assign back to the embedConfig input parameters. e.g.:

      const reportConfigNew: IReportEmbedConfiguration = {
           ...this.embedConfig,
           accessToken: response?.data?.accessToken,
          embedUrl: response?.data?.embedUrl[0]?.embedUrl
       }
    
       this.embedConfig= reportConfigNew;

    In this way the problem is - Embed url remains same and there is one check in PowerBIReportEmbedComponent like it will only proceed further if there is a change in embed url. I tried by adding the one extra query param to embed url as well but it keeps loading then and open the Something went wrong popup.

  2. In second way, I accessed the PowerBIReportEmbedComponent component like:

      @ViewChild(PowerBIReportEmbedComponent) reportObj!: PowerBIReportEmbedComponent;

    After that I used following code to update the token:

    const report = this.reportObj.getReport();
    report.setAccessToken(response?.data?.accessToken);

    The problem here is: It neither gives any error nor updates the token. I checked by getting the token again using following method and it is still accessing the old token (which is about to expire in some mins). So not able to get the solution in this way as well.

    const existingToken = report.config.accessToken;

Can someone help me here to fix the issue. Thanks in advance.

v-MadhavC commented 2 months ago

After updating the access token using 'setAccessToken()', you need to reload the report. While the report config gets updated with the new access token before reloading, the report may not use it until reloaded. You can verify this by checking the accessToken property of the report logged to the console.

Refer to the code snippet provided below for the report reload:

const report: Report = this.reportObj.getReport();
await report.setAccessToken('Your_New_Access_Token');
await report.reload();

Although reloading the report is a workaround, you can also setup an event listener to update the access token after the tab was inactive. Refer to the following documentation- Refresh the access token in Power BI embedded analytics | Microsoft Learn https://github.com/microsoft/powerbi-client-angular/issues/29#issuecomment-1923099092

jameswiseman76rlg commented 1 month ago

@jaspreet1234567 apologies for interloping. May I ask your strategy for checking expiry, e.g. what is executing your 10 minute check? Is this triggered from an event?

jaspreet1234567 commented 1 month ago

After updating the access token using 'setAccessToken()', you need to reload the report. While the report config gets updated with the new access token before reloading, the report may not use it until reloaded. You can verify this by checking the accessToken property of the report logged to the console.

Refer to the code snippet provided below for the report reload:

const report: Report = this.reportObj.getReport();
await report.setAccessToken('Your_New_Access_Token');
await report.reload();

Although reloading the report is a workaround, you can also setup an event listener to update the access token after the tab was inactive. Refer to the following documentation- Refresh the access token in Power BI embedded analytics | Microsoft Learn #29 (comment)

@v-MadhavC v If we reload the report then all the filters and pagination will also be reset which will not work in our case. We want to silently refresh the token so that user may not effected with it and he/she can do the work continuously.

Also even this functionality not exist in paginated-report component. I think still library is missing this for paginated report component.

jaspreet1234567 commented 1 month ago

@jaspreet1234567 apologies for interloping. May I ask your strategy for checking expiry, e.g. what is executing your 10 minute check? Is this triggered from an event?

@jameswiseman76rlg - I used following link to check the expiry of token after some interval and get the new token prior to 10 minutes of token expiry time.

https://learn.microsoft.com/en-us/javascript/api/overview/powerbi/refresh-token#manual-token-refresh-example

jaspreet1234567 commented 1 month ago

After updating the access token using 'setAccessToken()', you need to reload the report. While the report config gets updated with the new access token before reloading, the report may not use it until reloaded. You can verify this by checking the accessToken property of the report logged to the console.

Refer to the code snippet provided below for the report reload:

const report: Report = this.reportObj.getReport();
await report.setAccessToken('Your_New_Access_Token');
await report.reload();

Although reloading the report is a workaround, you can also setup an event listener to update the access token after the tab was inactive. Refer to the following documentation- Refresh the access token in Power BI embedded analytics | Microsoft Learn #29 (comment)

Hi @v-MadhavC - We tried this way, in our case - The control never comes back to next line after calling await report.setAccessToken('Your_New_Access_Token'); method. Seems like neither promise is not resolved in library nor throws the error in case of exception. What could be an issue there? Here is my configuration for the report:

 reportConfig: IEmbedConfiguration = {
   type: 'report',
  embedUrl: undefined,
  tokenType: models.TokenType.Embed,
 accessToken: undefined,
  settings: undefined,
  filters: undefined
};

this.reportConfig = {
   ...this.reportConfig,
   id: this.powerBiConfigResponse?.embedUrl[0].reportId,
   embedUrl: this.powerBiConfigResponse?.embedUrl[0].embedUrl,
   accessToken: this.powerBiConfigResponse?.accessToken
 };

Following is the code when we are trying to refresh the token:

  const report = this.reportObj.getReport();
  const existingToken = report.config.accessToken;
  await report.setAccessToken(response?.data?.accessToken);
  await report.reload();

Here the promise not resolved for setAccessToken method. Please check the configuration and let me know if we are doing anything wrong here.

v-MadhavC commented 1 month ago

Here in the code snippet below, we have provided the config that we are using. By referring to the following config, please make sure that the way you are fetching your new access token should be valid. In our approach, we are fetching it from an API Endpoint URL and then storing it and passing it into the 'setAccessToken()'. Could you try storing it and then passing it into the 'setAccessToken()'?

export interface ConfigResponse {
  Id: string;
  EmbedUrl: string;
  EmbedToken: {
    Token: string;
  };
}
  reportConfig: IReportEmbedConfiguration = {
    type: 'report',
    embedUrl: undefined,
    tokenType: models.TokenType.Embed,
    accessToken: undefined,
    settings: undefined,
  };

this.reportConfig = {
   ...this.reportConfig,
   id: reportConfigResponse.Id,
   embedUrl: reportConfigResponse.EmbedUrl,
   accessToken: reportConfigResponse.EmbedToken.Token,
    };

const newTokenResponse: ConfigResponse = await lastValueFrom(this.httpService.getEmbedConfig('YOUR_API_ENDPOINT_URL'));
await report.setAccessToken(newTokenResponse.EmbedToken.Token);
await report.reload();