0

I have created a custom connector that calls an API and generate report Now for that I need access token while connecting the connector first time we are able to generate the access token but once access token gets expired i want it should call refresh token and use the new access token from that.

The code contains the startlogin, FinishLogin and refreshtoken function


[Version = "2.0.0"]
section HelloWorld
;

[DataSource.Kind = "HelloWorld
", Publish = "HelloWorld
.Publish"]
// Define the shared navigation table to expose multiple functions
shared NavigationTable.Simple = () =>
    let
        // Define default values for the parameters (can be changed dynamically by the user)
        envelopeId = "1",
        // Example envelopeId (this can be dynamically set later)
        customerName = "2",
        // Example customerName (this can be dynamically set later)
        // Define the available functions in the navigation table
        objects = #table(
            {"Name", "Key", "Data", "ItemKind", "ItemName", "IsLeaf"},
            {
                {
                    "DSDB",
                    "Customers",
                    HelloWorld
.FunctionCallThatReturnsATable(envelopeId),
                    "Table",
                    "Table",
                    true
                }
                // ,
                // {"DSDB", "Products", HelloWorld
.FunctionCallWithFilter(customerName), "Table", "Table", true},
                // {"DSDB", "Test", HelloWorld
.Test(), "Table", "Table", true}
            }
        ),
        // Convert to a navigation table
        NavTable = Table.ToNavigationTable(objects, {"Key"}, "Name", "Data", "ItemKind", "ItemName", "IsLeaf")
    in
        NavTable;

// Function to get the base URL based on the selected environment
shared GetBaseUrl = (environment as text) =>
    let
        envBaseUrls = [
            Dev = "http://localhost:5275/odata",
            // Dev base URL
            Int = "https://staging.docusign.com/odata",
            // Staging base URL
            Prod = "https://api.docusign.com/odata"
            // Production base URL
        ],
        // Look up the base URL for the selected environment
        baseUrl = Record.FieldOrDefault(envBaseUrls, environment, "http://localhost:5275/odata")
        // Default to Dev if not found
    in
        baseUrl;

shared HelloWorld
.FunctionCallThatReturnsATable = (customerId as text) =>
    let
        // Get the access token from Power BI's OAuth flow
        token = Extension.CurrentCredential()[access_token],
        // Construct the API URL (you can replace this with the actual endpoint)
        url = "http://localhost:5275/odata/Customers",
        // Example URL
        // Fetch the data from the API with the dynamic envelopeId
        source = Json.Document(Web.Contents(url, [
            Headers = [
                #"Authorization" = "Bearer " & token
                // Add the token in the Authorization header
            ]
        ]))[value],
        // Convert the API response to a table
        asTable = Table.FromRecords(source)
    in
        asTable;


Table.ToNavigationTable = (
    table as table,
    keyColumns as list,
    nameColumn as text,
    dataColumn as text,
    itemKindColumn as text,
    itemNameColumn as text,
    isLeafColumn as text
) as table =>
    let
        tableType = Value.Type(table),
        newTableType = Type.AddTableKey(tableType, keyColumns, true) meta [
            NavigationTable.NameColumn = nameColumn,
            NavigationTable.DataColumn = dataColumn,
            NavigationTable.ItemKindColumn = itemKindColumn,
            Preview.DelayColumn = itemNameColumn,
            NavigationTable.IsLeafColumn = isLeafColumn
        ],
        navigationTable = Value.ReplaceType(table, newTableType)
    in
        navigationTable;

// OAuth2 Authentication setup
redirect_uri = "https://oauth.powerbi.com/views/oauthredirect.html";
state = "test";
// This can be a random string to track the state
client_id = "ec1f622b-a49d-44a7-a821-6ac9e0715d4a";
windowHeight = 800;
windowWidth = 800;

// The sample provides two code_challenge_method examples: "plain" and "S256".
code_challenge_method = "S256";

// Start OAuth login flow
StartLogin = (resourceUrl, state, display) =>
    let
        code_verifier = Text.NewGuid() & Text.NewGuid(),
        code_challenge =
            if (code_challenge_method = "plain") then
                code_verifier
            else if (code_challenge_method = "S256") then
                Base64Url.Encode(Crypto.CreateHash(CryptoAlgorithm.SHA256, Text.ToBinary(code_verifier)))
            else
                error "Unexpected code_challenge_method",
        AuthorizeUrl = "https://account-tk1.tk.docusign.dev/oauth/auth?"
            & Uri.BuildQueryString(
                [
                    response_type = "code",
                    client_id = client_id,
                    scope = "lens_api signature extended impersonation user_read",
                    state = state,
                    code_challenge_method = code_challenge_method,
                    code_challenge = code_challenge,
                    redirect_uri = redirect_uri
                ]
            ),
        windowHeight = 700,
        windowWidth = 700
    in
        [
            LoginUri = AuthorizeUrl,
            CallbackUri = redirect_uri,
            WindowHeight = windowHeight,
            WindowWidth = windowWidth,
            Context = code_verifier
        ];

// Finalize OAuth login and obtain the token
FinishLogin = (context, callbackUri, state) =>
    let
        Parts = Uri.Parts(callbackUri)[Query]
    in
        TokenMethod("authorization_code", Parts[code], context);

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

// Token exchange method
TokenMethod = (grant_type, code, code_verifier) =>
    let
        // Define the base URL for the token request
        tokenUrl = "https://account-tk1.tk.docusign.dev/oauth/token",
        // Construct the body based on the grant type
        body =
            if grant_type = "authorization_code" then
                Uri.BuildQueryString(
                    [
                        grant_type = "authorization_code",
                        code = code,
                        code_verifier = code_verifier,
                        client_id = client_id
                    ]
                )
            else if grant_type = "refresh_token" then
                Uri.BuildQueryString([
                    grant_type = "refresh_token",
                    refresh_token = code,
                    client_id = client_id
                ])
            else
                error "Unsupported grant_type",
        // Send the token request
        Response = Web.Contents(
            tokenUrl,
            [
                Content = Text.ToBinary(body),
                Headers = [
                    #"Content-type" = "application/x-www-form-urlencoded",
                    #"Accept" = "application/json"
                ]
            ]
        ),
        // Parse the JSON response
        Parts = Json.Document(Response),
        // Extract the access token, refresh token, and expiration info
        accessToken = Parts[access_token],
        refreshToken = if Record.HasFields(Parts, "refresh_token") then Parts[refresh_token] else null,
        // Handle the case where no refresh token is provided
        expiresIn = Parts[expires_in],
        // Calculate the expiration date for the access token
        expiresAt = DateTime.LocalNow() + #duration(0, 0, 0, expiresIn / 60),
        // Return the access token, refresh token, and expiration time
        result = [
            access_token = accessToken,
            refresh_token = refreshToken,
            expires_at = expiresAt
        ]
    in
        result;

// Data Source Kind description (authentication)
HelloWorld
 = [
    TestConnection = (dataSourcePath) => {"HelloWorld
.ODataFeed"},
    Authentication = [
        OAuth2 = [
            StartLogin = StartLogin,
            FinishLogin = FinishLogin,
            Refresh = Refresh
        ]
    ],
    Label = Extension.LoadString("DataSourceLabel")
];


// Icon definitions for the connector UI
HelloWorld
.Icons = [
    Icon16 = {
        Extension.Contents("HelloWorld
16.png"),
        Extension.Contents("HelloWorld
20.png"),
        Extension.Contents("HelloWorld
24.png"),
        Extension.Contents("HelloWorld
32.png")
    },
    Icon32 = {
        Extension.Contents("HelloWorld
32.png"),
        Extension.Contents("HelloWorld
40.png"),
        Extension.Contents("HelloWorld
48.png"),
        Extension.Contents("HelloWorld
64.png")
    }
];

Base64Url.Encode = (s) =>
    Text.Replace(
        Text.Replace(Text.BeforeDelimiter(Binary.ToText(s, BinaryEncoding.Base64), "="), "+", "-"), "/", "_"
    );

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.