Search code examples
angularazurepowerbipowerbi-embeddedmsal

PowerBI Embed in Angular "User Owns Data" | Getting InteractionRequiredAuthError: AADSTS65001 while generating powerbi access token


I am trying to embed a PowerBI report in angular web application using "User Owns Data" method.

Design Philosophy

The idea is to login to my web application where Azure AD authenticates the user, then the user provides this Azure AD provided access token to the power bi service and get the embed token for the report. Of course, the user needs to have access to organization's power bi and the report. I have followed these steps.

Set Up App Registration with below API permission

enter image description here

Publish report from premium workspace in app.powerbi.com

  • I have pro license and Admin access to the workspace
  • I published the report
  • I granted access to my team members

Created an angular web app

auth.service.ts
export class AuthService {
  private msalConfig = {
    auth: {
      clientId: environment.clientId,
      authority: environment.authority,
      redirectUri: environment.redirectUri,
    },
  };

  private msalInstance = new Msal.UserAgentApplication(this.msalConfig);

  login() {
    console.log(this.msalInstance)
    return this.msalInstance.loginPopup({
      scopes: ['openid', 'profile', 'user.read'],
    });
  }

  getAccessToken() {
    return this.msalInstance.acquireTokenSilent({
      scopes: ['openid', 'profile', 'Tenant.Read.All'],
    });
  }
} 

I used msal ClientId I used here is from the earlier App Registration step and the redirect url is 'http://localhost/4200'.

report.component.html

<powerbi-report [embedConfig]="embedConfig"></powerbi-report>

report.component.ts

export class ReportComponent implements OnInit {
  @ViewChild(PowerBIReportEmbedComponent)
  reportObj!: PowerBIReportEmbedComponent;
  embedConfig!: IReportEmbedConfiguration;
  eventHandlersMap = new Map([
    [
      'loaded',
      (e: any) => {
        console.log('Loaded:', e);
      },
    ],
    [
      'rendered',
      (e: any) => {
        console.log('Rendered:', e);
      },
    ],
  ]) as Map<
    string,
    (event?: service.ICustomEvent<any>, embeddedEntity?: Embed) => void | null
  >;

  constructor(private authService: AuthService) {}

  ngOnInit(): void {
    this.authService
      .login()
      .then((res: any) => {
        console.log('Login Success', res);
        this.authService
          .getAccessToken()
          .then((r: any) => {
            console.log(r);
            this.updateCongiguration(r.accessToken);
          })
          .catch((e) => {
            console.error('Error fetching access token:', e);
          });
      })
      .catch((err) => {
        console.error('Error during login:', err);
      });
  }

  updateConfiguration(accessToken: string) {
    this.embedConfig = {
      type: 'report',
      embedUrl: environment.embedUrl,
      tokenType: models.TokenType.Aad,
      accessToken,
      settings: {
        panes: {
          filters: {
            expanded: false,
            visible: true,
          },
        },
        background: models.BackgroundType.Transparent,
      },
    };
  }
}
package.json
 "msal": "^1.4.18",
 "powerbi-client-angular": "^3.0.5",

The error

When the component initializes, msal successfully completes the login. After successful login, when it tries to get the powerbi access token I am getting below error -

Error fetching access token: InteractionRequiredAuthError:
AADSTS65001: The user or administrator has not consented to use the
application with ID {client id of my app registration} named {my app
registration name}. Send an interactive authorization request for this
user and resource. Trace ID: {trace id} Correlation ID: {correlation
id}

I think the issue is at the API access provided in the app registration for my web app, but I am not sure. What I am doing wrong? Any help will be appreciated.


Solution

  • Note that, interactive flows only work with permissions of Delegated type. But Tenant.Read.All is an Application type permission that won't work in this scenario.

    Initially, I too got same error when I tried to generate Power BI token with Tenant.Read.All scope like this:

    enter image description here

    To resolve the error, make sure to grant Power BI permissions of Delegated type with admin consent as below:

    enter image description here

    When I ran the code again changing scope value, I got the Power BI access token after successful user login:

    enter image description here

    To confirm that, I decoded the above access token in jwt.ms website and checked scp claim value:

    enter image description here

    In your case, modify scopes parameter values in your code like this:

    auth.service.ts:

    export class AuthService {
      private msalConfig = {
        auth: {
          clientId: environment.clientId,
          authority: environment.authority,
          redirectUri: environment.redirectUri,
        },
      };
    
      private msalInstance = new Msal.UserAgentApplication(this.msalConfig);
    
      login() {
        console.log(this.msalInstance)
        return this.msalInstance.loginPopup({
          scopes: ['https://analysis.windows.net/powerbi/api/Report.ReadWrite.All'],
        });
      }
    
      getAccessToken() {
        return this.msalInstance.acquireTokenSilent({
          scopes: ['https://analysis.windows.net/powerbi/api/Report.ReadWrite.All'],
        });
      }
    } 
    

    Reference:

    Embed Token - Generate Token - REST API (Power BI REST APIs) | Microsoft