PowerQuery icon indicating copy to clipboard operation
PowerQuery copied to clipboard

Custom Data Connector issue with authentication

Open AfsarP1 opened this issue 4 years ago • 3 comments

Hi Matt

I have looked at your videos and Git hub codes and they are commendable. I have created a custom data connector which connects to our cloud environment using Oauth login method. Unfortunately, I've ended up with an issue which is getting me nowhere. I have spent days on google search but nothing relevant comes up which could solve my issue.

To keep it simple. I'm connecting to our cloud environment using client_id, username and password but not the client_secret. When I run the code, I get an error stating :

"AADSTS650056: Misconfigured application. This could be due to one of the following: the client has not listed any permissions for 'AAD Graph' in the requested permissions in the client's application registration. Or, the admin has not consented in the tenant. Or, check the application identifier in the request to ensure it matches the configured client application identifier. Or, check the certificate in the request to ensure it's valid. Please contact your admin to fix the configuration or consent on behalf of the tenant. "

When I google it talks about registering my application on Assure active directory which shouldn't be the case because the client_id, API username and password is actively used. We have a Powershell script with same credentials that connects successfully but I'm receiving an error with my custom connector.

As a last resort I'm reaching out to you as you are the best at custom connector.

Appreciate if you could put some light on this error.

Thanks

AfsarP1 avatar Jun 23 '20 10:06 AfsarP1

Sharing my code:

// This file contains your Data Connector logic section System;

client_id = Text.FromBinary(Extension.Contents("client_id.txt")); username = Text.FromBinary(Extension.Contents("username.txt")); password = Text.FromBinary(Extension.Contents("password.txt")); redirect_uri = "https://ourdomain/oauth2/authresp"; token_uri = "https://ourdomain/oauth2/v2.0/token"; //Used to retrieve an access token authorize_uri = "https://ourdomain/oauth2/authorize"; logout_uri = "https://login.microsoftonline.com/logout.srf";

// Login modal window dimensions windowWidth = 720; windowHeight = 1024;

// OAuth2 scope scope_prefix = "https://ourdomian.com"; scopes = { "daily", "User.Read", "openid" //".Read.All", //"IdentityProvider.Read.All" //"client_id"

//It can be delegated permission or app permission https://docs.microsoft.com/en-us/graph/auth/auth-concepts#microsoft-graph-permissions };

[DataSource.Kind="System", Publish="System.Publish"] shared System.Contents = (url as text) =>

let source = Json.Document(Web.Contents(url)) //If the data is returned from the datasource in JSON format

in source;

// Data Source Kind description System = [ TestConnection = (dataSourcePath) => { "System.Contents", dataSourcePath }, Authentication = [ OAuth = [ StartLogin=StartLogin, FinishLogin=FinishLogin, Refresh=Refresh, Logout=Logout ] ],

Label = Extension.LoadString("DataSourceLabel") ];

// Data Source UI publishing description System.Publish = [ Beta = true, Category = "Other", ButtonText = { Extension.LoadString("ButtonTitle"), Extension.LoadString("ButtonHelp") }, LearnMoreUrl = "https://powerbi.microsoft.com/", //This can be replaced with our System URI. This is a help URI which gives more info about this connector. SourceImage = System.Icons, SourceTypeImage = System.Icons ];

//Helper functions for OAuth2: StartLogin, FinishLogin, Refresh, Logout. Start Login definition: StartLogin = (resourceUrl, state, display) => let authorizeUrl = authorize_uri & "?" & Uri.BuildQueryString([ client_id = client_id, response_type = "code", redirect_uri = redirect_uri, state = state, scope = "offline_access " & GetScopeString(scopes, scope_prefix) // or GetScopeString(scopes, scope_prefix) //response_mode = "query", //login = "login" ]) in [ LoginUri = authorizeUrl, CallbackUri = redirect_uri, WindowHeight = 720, WindowWidth = 1024, Context = null ];

//Function that extracts the access_token and other properties related to the OAuth flow.: FinishLogin = (context, callbackUri, state) => let // parse the full callbackUri, and extract the Query string parts = Uri.Parts(callbackUri)[Query], // if the query string contains an "error" field, raise an error // otherwise call TokenMethod to exchange our code for an access_token result = if (Record.HasFields(parts, {"error", "error_description"})) then error Error.Record(parts[error], parts[error_description], parts) else TokenMethod("authorization_code", "code", parts[code]) in result;

//Function that retrieves a new access token from a refresh token. //Refresh definition: Refresh = (resourceUrl, refresh_token) => TokenMethod("authorization_code", "code", refresh_token);

//Function that invalidates the user's current access token: //Logout definition: Logout = (token) => logout_uri;

//Below definition is to exchange an auth code for an access token: TokenMethod = (grantType, tokenField, code) => let queryString = [ client_id = client_id, grant_type = "authorization_code", //grantType, //"authorization_code", //This can also be grant_type scope = "offline_access " & GetScopeString(scopes, scope_prefix),//Optional redirect_uri = redirect_uri //client_id = client_id

], queryWithCode = Record.AddField(queryString, tokenField, code),

tokenResponse = Web.Contents(token_uri, [ Content = Text.ToBinary(Uri.BuildQueryString(queryWithCode)), Headers = [ //#"Authorization" = "Basic XXXXXXXXXXX encoded client key and secrect", #"Content-type" = "application/x-www-form-urlencoded", #"Accept" = "application/json" ], ManualStatusHandling = {400} ]), body = Json.Document(tokenResponse), result = if (Record.HasFields(body, {"error", "error_description"})) then error Error.Record(body[error], body[error_description], body) else body in result;

Value.IfNull = (a, b) => if a <> null then a else b;

GetScopeString = (scopes as list, optional scopePrefix as text) as text => let prefix = Value.IfNull(scopePrefix, ""), addPrefix = List.Transform(scopes, each prefix & _), asText = Text.Combine(addPrefix, " ") in asText;

System.Icons = [ Icon16 = { Extension.Contents("System16.png"), Extension.Contents("System20.png"), Extension.Contents("System24.png"), Extension.Contents("System32.png") }, Icon32 = { Extension.Contents("System32.png"), Extension.Contents("System40.png"), Extension.Contents("System48.png"), Extension.Contents("System64.png") } ];

AfsarP1 avatar Jun 23 '20 10:06 AfsarP1

Hey @AfsarP1 ! I'd highly recommend that you post your question on the official Microsoft Power BI Custom Connectors repo here: https://github.com/microsoft/DataConnectors/

You've created an issue on Matt's very own repo instead of the official Microsoft one.

Based on what I've read, I'm not entirely sure if you're using Microsoft's OAuth based on AAD an app registrations or if you're trying to use something specific to something else. Sorry that I can't be of help, but I'm sure that you could get some guidance from the MSFT team if you post the issue on their repo.

migueesc123 avatar Jun 23 '20 13:06 migueesc123

Hi @migueesc123

Thanks for the reply.

Yes, I created the issue here because I felt Matt is the last resource that could help(after looking at his github codes and videos). I had created an issue on the Microsoft Power BI Custom Connectors repo but didn't receive any response:

https://github.com/microsoft/DataConnectors/issues/304

AfsarP1 avatar Jun 24 '20 08:06 AfsarP1