How to properly build a Clio Power Query custom connector for Power BI?

268 Views Asked by At

I am building a custom Power Query connector for Clio. It is my first PQ custom connector so I need to know 2 things:

  1. How do I work in the token handling in the Token Handling section?
  2. Once I get that working, how do I make the Client ID and Secret a dynamic reference to a separate file? I don't like the idea of hardcoding that into something.

Here is my code:

section Clio;

[DataSource.Kind="Clio", Publish="Clio.Publish"]
shared Clio.Contents = (optional message as text) =>
    let
        _message = if (message <> null) then message else "(no message)",
        a = "Hello from Clio: " & _message
    in
        a;

OAuthBaseUrl = "https://app.clio.com/api/v4";

// Data Source Kind description
Clio = [
    Authentication = [
        OAuth = [
            StartLogin = StartLogin,
            FinishLogin = FinishLogin
        ]
    ],
    Label = Extension.LoadString("DataSourceLabel")
];

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

StartLogin = (resourceUrl, state, display) =>
    let
        AuthorizeUrl = OAuthBaseUrl & "/oauth/authorize?" & Uri.BuildQueryString([
            response_type = "code",
            client_id = client_id_code,
            redirect_uri = "https://app.clio.com/oauth/approval",
            state = state
            ])
    in
        [
            LoginUri = "https://app.clio.com",
            CallbackUri = "https://app.clio.com/oauth/approval",
            WindowHeight = 1080,
            WindowWidth = 720
        ];

FinishLogin = (context, callbackUri, state) =>
    let
        Parts = Uri.Parts(callbackUri)[Query]
    in
        TokenMethod(Parts[code], "authorization_code", context);

//Token Handling

TokenMethod = (grant_type, optional verifier) =>
    let
        query = [
            client_id = client_id_code,
            client_secret = client_secret_code,
            grant_type = "refresh_token",
            refresh_token = I_don't_know_what_to_put_here
        ],
 
        ManualHandlingStatusCodes= {400,403},
        
        Response = Web.Contents(OAuthBaseUrl & "/token", [
            Content = Text.ToBinary(Uri.BuildQueryString(query)),
            Headers = [
                #"Content-type" = "application/x-www-form-urlencoded",
                #"Accept" = "application/json"
            ],
            ManualStatusHandling = ManualHandlingStatusCodes
        ]),
        Parts = Json.Document(Response)
    in
        // check for error in response
        if (Parts[error]? <> null) then 
            error Error.Record(Parts[error], Parts[message]?)
        else
            Parts;

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

Clio.Icons = [
    Icon16 = { Extension.Contents("Clio16.png"), Extension.Contents("Clio20.png"), Extension.Contents("Clio24.png"), Extension.Contents("Clio32.png") },
    Icon32 = { Extension.Contents("Clio32.png"), Extension.Contents("Clio40.png"), Extension.Contents("Clio48.png"), Extension.Contents("Clio64.png") }
];
0

There are 0 best solutions below