Reputation: 415
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), "="), "+", "-"), "/", "_"
);
Upvotes: 1
Views: 50