1
votes

When we tried to embed ‘Power BI embedded’ in our existing application, we encountered a 406 not accepted error. To ensure that this was not caused by our own application we used the sample code in the power bi sample repository: https://github.com/Microsoft/PowerBI-Developer-Samples. We used the "App Owns Data" scenario, because our end users do not own Power BI Pro licenses. We followed all the necessary configuration steps and provided the necessary credentials/id's in the web.config.

At our first attempt to run the application, we got a connection closed error. After some research, we found out that this was caused by an incorrect TLS version. Adding ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; to the controller solved this.

The next error we faced was at the following line of code:

var authenticationResult = await authenticationContext.AcquireTokenAsync(ResourceUrl, ApplicationId, credential);

This line ended in an http exception: 406 - Not Acceptable. When we inspected the traffic with Fiddler, this error was deemed logical, because our Azure AD is referring to our ADFS server as the relying party with an accept header for JSON content, while our ADFS returned an xml body. Our conclusion was that the AcquireTokenAsync does not work correctly with our corporate Azure AD / ADFS environment. To investigate this, we ran several tests:

  1. Instead of using the standard ADAL library, we tried to use the MSAL lib. However, this resulted in the same error.

  2. Doing a (raw) post request to the Azure AD to obtain the auth token with the following code:

    try
    {
        client.DefaultRequestHeaders.Add("Cache-Control", "no-cache");
        _result = await client.PostAsync(
            new Uri("https://login.windows.net/common/oauth2/token"), new FormUrlEncodedContent(
                new[]
                {
                new KeyValuePair("resource", "https://analysis.windows.net/powerbi/api"),
                new KeyValuePair("client_id", ClientId),
                new KeyValuePair("grant_type", "password"),
                new KeyValuePair("username", UserName),
                new KeyValuePair("password", Password),
                new KeyValuePair("scope", "openid"),
                }));
    }
    catch (HttpOperationException ex)
    {
        //Bad Request
        var content = ex.Response.Content;
        Console.WriteLine(content);
    }

This resulted in the following error, which we were not able to solve:

{"error":"invalid_grant","error_description":"AADSTS70002: Error validating credentials. AADSTS50126: Invalid username or password\r\nTrace ID: b8a97eae-63a4-4d56-8afd-e18eb7b02800\r\nCorrelation ID: 3e168d8f-61ab-4b7f-b9c4-6ae7870c5e06\r\nTimestamp: 2018-12-03 12:59:38Z","error_codes":[70002,50126],"timestamp":"2018-12-03 12:59:38Z","trace_id":"b8a97eae-63a4-4d56-8afd-e18eb7b02800","correlation_id":"3e168d8f-61ab-4b7f-b9c4-6ae7870c5e06"}

  1. We performed an interactive logon by using the following code with success:

    var authenticationResult = await authenticationContext.AcquireTokenAsync(ResourceUrl, ApplicationId, new Uri("http://localhost:42734/"), new PlatformParameters(PromptBehavior.Auto));

However, this is not ideal, because we do not want our end-users to (interactively) login with a proxy account in our AD every time they use Power BI embedded in our application :)

  1. Following the blog from microsoft about this scenario also yielded no results: https://blogs.msdn.microsoft.com/azuredev/2018/01/22/accessing-the-power-bi-apis-in-a-federated-azure-ad-setup/

The question was how to fix this.... See the answer below that we found after months (!) of searching.

1

1 Answers

0
votes

After months of searching, a colleague of mine at the other end of the globe helped me out. The solution was simple: use a proxy account that is created in the Azure AD, but not known in the relying AD. This way the authentication will take place in the Azure AD, and the relying ADFS is not used. This prevents all the errors that we faced and will enable ADAL and MSAL authentication.

When we started to embed Power BI in our own .NET Core application we found out that the post request is currently the best option because the we cannot find appropriate methods for username/password auth in the .NET Core libs. The post request also works fine with solution mentioned before.

I hope this hint will save somebody the time it took us...