Skip to main content
cancel
Showing results for 
Search instead for 
Did you mean: 

Register now to learn Fabric in free live sessions led by the best Microsoft experts. From Apr 16 to May 9, in English and Spanish.

Reply
powerbi4ever
New Member

Power Query Custom Connector

Hi Experts,

I have created a custom Power query connector for Procore with OAUTH2 authorization with autorization code as mentioned by procore developer team here ( following Microsoft's guide).
I am able to login and extract data but everytime I input a different URL as an source, the previous authentication becomes invalid and it again asks for authentication and keeps on asking whenever there is a new url.
I suspect my code is not able to refresh token and hence it keeps on asking for a new token. Can anyone guide me on how I can :
1. Make token refresh fuctionality to work in my code ? OR
2. Include all required tables\endpoints inside the connector code itself so that it will ingest all data in one go while connecting automatically. 
Any help will be highly appreciated and I have spent ages over it.

Below is my code for your reference:

 

 

 

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

// Procore OAuth2 values
client_id = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
client_secret = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
redirect_uri = "https://oauth.powerbi.com/views/oauthredirect.html";
token_uri = "https://login.procore.com/oauth/token";
authorize_uri = "https://login.procore.com/oauth/authorize";
logout_uri = "https://login.microsoftonline.com/logout.srf";

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

// OAuth2 scope
scope_prefix = "";
scopes = {
    ""
};


[DataSource.Kind="ProcoreConnector", Publish="ProcoreConnector.Publish"]
shared ProcoreConnector.Contents = (url as text) =>
    let
        source = Json.Document(Web.Contents(url))
    in
        source; 

// Data Source Kind description
ProcoreConnector= [
    TestConnection = (dataSourcePath) => { "ProcoreConnector.Contents", dataSourcePath },
    Authentication = [
        OAuth = [
            StartLogin=StartLogin,
            FinishLogin=FinishLogin,
            Refresh=Refresh,
            Logout=Logout
            
        ]
    ],
    Label = Extension.LoadString("DataSourceLabel")
];

// Data Source UI publishing description
ProcoreConnector.Publish = [
    Beta = true,
    Category = "Other",
    ButtonText = { Extension.LoadString("ButtonTitle"), Extension.LoadString("ButtonHelp") },
    LearnMoreUrl = "https://developers.procore.com/",
    SourceImage = ProcoreConnector.Icons,
    SourceTypeImage = ProcoreConnector.Icons
];

// Helper functions for OAuth2: StartLogin, FinishLogin, Refresh, Logout
StartLogin = (resourceUrl, state, display) =>
    let
        authorizeUrl = authorize_uri & "?" & Uri.BuildQueryString([
            response_type = "code",
            client_id = client_id,  
            redirect_uri = redirect_uri
        ])
    in
        [
            LoginUri = authorizeUrl,
            CallbackUri = redirect_uri,
            WindowHeight = 720,
            WindowWidth = 1024,
            Context = null
        ];

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;

Refresh = (resourceUrl, refresh_token) => TokenMethod("refresh_token", "refresh_token", refresh_token);

Logout = (token) => logout_uri;


// see "Exchange code for access token: https://developers.procore.com/documentation/oauth-installed-apps for details
TokenMethod = (grantType, tokenField, code) =>
    let
        queryString = [
            grant_type = "authorization_code",
            redirect_uri = redirect_uri,
            client_id = client_id,
            client_secret = client_secret
        ],
        queryWithCode = Record.AddField(queryString, tokenField, code),

        tokenResponse = Web.Contents(token_uri, [
            Content = Text.ToBinary(Uri.BuildQueryString(queryWithCode)),
            Headers = [
                #"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;
       

ProcoreConnector.Icons = [
    Icon16 = { Extension.Contents("ProcoreConnector16.png"), Extension.Contents("ProcoreConnector20.png"), Extension.Contents("ProcoreConnector24.png"), Extension.Contents("ProcoreConnector32.png") },
    Icon32 = { Extension.Contents("ProcoreConnector32.png"), Extension.Contents("ProcoreConnector40.png"), Extension.Contents("ProcoreConnector48.png"), Extension.Contents("ProcoreConnector64.png") }
];

 

 

 

 

4 REPLIES 4
PatrickM
Frequent Visitor

Did you ever solve this? I'm dealing with the same issue. Thanks

lbendlin
Super User
Super User

A new URL will always cause a re-authentication challenge.  You need to pack the variable part of your URL into the RelativePath and Query  portions.

Anonymous
Not applicable

How did you develop a Custom Connector on 2022? The Power Query SDK does not work anymore

v-yingjl
Community Support
Community Support

Hi @powerbi4ever ,

Not familiar with creating custom connector, but for the authentication in Power Query, perhaps you can refer this document which introduces the authentication method indetails which could help you in some ways:

Handling Authentication 

 

In addition, since it may related to the development for a custom connector, you can create a post in Developer forum on the community.

 

Best Regards,
Community Support Team _ Yingjie Li
If this post helps, then please consider Accept it as the solution to help the other members find it more quickly.

Helpful resources

Announcements
Microsoft Fabric Learn Together

Microsoft Fabric Learn Together

Covering the world! 9:00-10:30 AM Sydney, 4:00-5:30 PM CET (Paris/Berlin), 7:00-8:30 PM Mexico City

PBI_APRIL_CAROUSEL1

Power BI Monthly Update - April 2024

Check out the April 2024 Power BI update to learn about new features.

April Fabric Community Update

Fabric Community Update - April 2024

Find out what's new and trending in the Fabric Community.

Top Solution Authors
Top Kudoed Authors