<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>topic Multiple Authentication Issue with Custom Connector in Developer</title>
    <link>https://community.fabric.microsoft.com/t5/Developer/Multiple-Authentication-Issue-with-Custom-Connector/m-p/2443568#M35396</link>
    <description>&lt;P&gt;Hi Experts,&lt;/P&gt;&lt;P&gt;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).&lt;BR /&gt;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.&lt;BR /&gt;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 :&lt;BR /&gt;1. Make token refresh fuctionality to work in my code ? OR&lt;BR /&gt;2. Include all required tables\endpoints inside the connector code itself so that it will ingest all data in one go while connecting automatically.&lt;BR /&gt;Any help will be highly appreciated and I have spent ages over it.&lt;/P&gt;&lt;P&gt;Below is my code for your reference:&lt;BR /&gt;&lt;BR /&gt;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;LI-CODE lang="markup"&gt;// 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) =&amp;gt;
    let
        source = Json.Document(Web.Contents(url))
    in
        source; 

// Data Source Kind description
ProcoreConnector= [
    TestConnection = (dataSourcePath) =&amp;gt; { "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) =&amp;gt;
    let
        authorizeUrl = authorize_uri &amp;amp; "?" &amp;amp; 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) =&amp;gt;
    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) =&amp;gt; TokenMethod("refresh_token", "refresh_token", refresh_token);

Logout = (token) =&amp;gt; logout_uri;


// see "Exchange code for access token: https://developers.procore.com/documentation/oauth-installed-apps for details
TokenMethod = (grantType, tokenField, code) =&amp;gt;
    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") }
];&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
    <pubDate>Thu, 07 Apr 2022 13:21:08 GMT</pubDate>
    <dc:creator>powerbi4ever</dc:creator>
    <dc:date>2022-04-07T13:21:08Z</dc:date>
    <item>
      <title>Multiple Authentication Issue with Custom Connector</title>
      <link>https://community.fabric.microsoft.com/t5/Developer/Multiple-Authentication-Issue-with-Custom-Connector/m-p/2443568#M35396</link>
      <description>&lt;P&gt;Hi Experts,&lt;/P&gt;&lt;P&gt;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).&lt;BR /&gt;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.&lt;BR /&gt;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 :&lt;BR /&gt;1. Make token refresh fuctionality to work in my code ? OR&lt;BR /&gt;2. Include all required tables\endpoints inside the connector code itself so that it will ingest all data in one go while connecting automatically.&lt;BR /&gt;Any help will be highly appreciated and I have spent ages over it.&lt;/P&gt;&lt;P&gt;Below is my code for your reference:&lt;BR /&gt;&lt;BR /&gt;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;LI-CODE lang="markup"&gt;// 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) =&amp;gt;
    let
        source = Json.Document(Web.Contents(url))
    in
        source; 

// Data Source Kind description
ProcoreConnector= [
    TestConnection = (dataSourcePath) =&amp;gt; { "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) =&amp;gt;
    let
        authorizeUrl = authorize_uri &amp;amp; "?" &amp;amp; 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) =&amp;gt;
    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) =&amp;gt; TokenMethod("refresh_token", "refresh_token", refresh_token);

Logout = (token) =&amp;gt; logout_uri;


// see "Exchange code for access token: https://developers.procore.com/documentation/oauth-installed-apps for details
TokenMethod = (grantType, tokenField, code) =&amp;gt;
    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") }
];&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Thu, 07 Apr 2022 13:21:08 GMT</pubDate>
      <guid>https://community.fabric.microsoft.com/t5/Developer/Multiple-Authentication-Issue-with-Custom-Connector/m-p/2443568#M35396</guid>
      <dc:creator>powerbi4ever</dc:creator>
      <dc:date>2022-04-07T13:21:08Z</dc:date>
    </item>
    <item>
      <title>Re: Multiple Authentication Issue with Custom Connector</title>
      <link>https://community.fabric.microsoft.com/t5/Developer/Multiple-Authentication-Issue-with-Custom-Connector/m-p/2448543#M35450</link>
      <description>&lt;P&gt;&lt;FONT face="tahoma,arial,helvetica,sans-serif"&gt;Hi&amp;nbsp;&lt;a href="https://community.fabric.microsoft.com/t5/user/viewprofilepage/user-id/374526"&gt;@powerbi4ever&lt;/a&gt;,&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="tahoma,arial,helvetica,sans-serif"&gt;I think this data connector works as excepted. (current power bi does not support global credentials for data source usage)&lt;/FONT&gt;&lt;BR /&gt;&lt;FONT face="tahoma,arial,helvetica,sans-serif"&gt;When you change the current URL, it means you are working with a different data source, so it will require you to input the new credentials.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="tahoma,arial,helvetica,sans-serif"&gt;For the folder or SharePoint connector, they have required credentials of the parent level permissions, then their connector can iterator and list their child contents at the same time.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="tahoma,arial,helvetica,sans-serif"&gt;Regards,&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="tahoma,arial,helvetica,sans-serif"&gt;Xiaoxin Sheng&lt;/FONT&gt;&lt;/P&gt;</description>
      <pubDate>Mon, 11 Apr 2022 06:48:00 GMT</pubDate>
      <guid>https://community.fabric.microsoft.com/t5/Developer/Multiple-Authentication-Issue-with-Custom-Connector/m-p/2448543#M35450</guid>
      <dc:creator>Anonymous</dc:creator>
      <dc:date>2022-04-11T06:48:00Z</dc:date>
    </item>
  </channel>
</rss>

