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

Calling all Data Engineers! Fabric Data Engineer (Exam DP-700) live sessions are back! Starting October 16th. Sign up.

Reply
VinceG0214
Frequent Visitor

Custom Data Connector Oauth2

I am trying to build a custom data connector to get our IT ticket information from our ticketing system. Our ticketing system does offer an API that uses Oauth2 and a new refresh token every 60 minutes. Everything looks good but when I use the custom data connector in PowerBI Desktop I am still getting an error saying "invalid_token." Can anyone help me with this?

 

section GTAConnector;

client_id = Text.FromBinary(Extension.Contents("client_id.txt"));
client_secret = Text.FromBinary(Extension.Contents("client_secret.txt"));
redirect_uri = "https://oauth.powerbi.com/views/oauthredirect.html";
token_uri = "https://api.getgo.com/oauth/v2/token";
authorize_uri = "https://api.getgo.com/oauth/v2/authorize";
logout_uri = "https://login.microsoftonline.com/logout.srf";

windowWidth = 720;
windowHeight = 1024;


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

GTAConnector = [
    TestConnection = (dataSourcePath) => { "GTAConnector.Contents", dataSourcePath },
    Authentication = [
        OAuth = [
            StartLogin=StartLogin,
            FinishLogin=FinishLogin,
            Refresh=Refresh,
            Logout=Logout
        ]
    ],
    Label = Extension.LoadString("DataSourceLabel")
];

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

StartLogin = (resourceUrl, state, display) =>
    let
        authorizeUrl = authorize_uri & "?" & Uri.BuildQueryString([
            client_id = client_id,
            response_type = "code",
            redirect_uri = redirect_uri
        ])
    in
        [
            LoginUri = authorizeUrl,
            CallbackUri = redirect_uri,
            WindowHeight = 720,
            WindowWidth = 1024,
            Context = null
        ];

FinishLogin = (context, callbackUri, state) =>
    let
        parts = Uri.Parts(callbackUri)[Query],
        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("authorization_code", "code", refresh_token);

Logout = (token) => logout_uri;

TokenMethod = (grantType, tokenField, code) =>
    let
        queryString = [
            grant_type = "authorization_code",
            redirect_uri = redirect_uri

        ],
        queryWithCode = Record.AddField(queryString, tokenField, code),

        tokenResponse = Web.Contents(token_uri, [
            Content = Text.ToBinary(Uri.BuildQueryString(queryWithCode)),
            Headers = [
                #"Authorization" = "Basic XXXXXXXXXXX encoded client key and secrect",
                #"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;

Value.IfNull = (a, b) => if a <> null then a else b;
        

GTAConnector.Icons = [
    Icon16 = { Extension.Contents("GTAConnector16.png"), Extension.Contents("GTAConnector20.png"), Extension.Contents("GTAConnector24.png"), Extension.Contents("GTAConnector32.png") },
    Icon32 = { Extension.Contents("GTAConnector32.png"), Extension.Contents("GTAConnector40.png"), Extension.Contents("GTAConnector48.png"), Extension.Contents("GTAConnector64.png") }
];

 

 

4 REPLIES 4
VinceG0214
Frequent Visitor

This connector is now working when I refresh it in Power BI Desktop but will not refresh in the Power BI service online. I am getting an error that says the data source credentials are invalid. When I select "Edit Credentials" and sign in the login windown just refreshes and doesnt do anything. Does anyone have an idea what the issue here is? 

Data Source Credentials Invalid.JPGOauth2 sign in.JPG

Hi @VinceG0214,

as @v-juanli-msft said, the code is long, we can't test it and therefore it is complicated to help. But I think I see a problem because I've had a similar one.

The function GTAConnector.Contents expects an URL but you get a JSON file where the first element is url - you can see it on the screenshot in PBI Service.

It is described somewhere here: https://docs.microsoft.com/en-us/power-query/samples/trippin/readme but unfortunately I can't find the exact spot right now 😞

Try followings:

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

Here is the documentation for what I am trying to accomplish and the endpoint is https://deskapi.gotoassist.com/v2/incidents. Am I going about this wrong?

 

GTAOauth.JPGGTAOauthCall.JPG

v-juanli-msft
Community Support
Community Support

Hi @VinceG0214 

You M queries are too complex and seems not valid.

To create an M query in the Query Editor, you follow this basic process:

Create a series of query formula steps that start with the let statement.,

Output a query formula step using the in statement. Generally, the last query step is used as the in final data set result.

https://docs.microsoft.com/en-us/powerquery-m/quick-tour-of-the-power-query-m-formula-language

 

Please take a look at the following examples about how to connect to API in Power BI Desktop.
Get Data from Twitter API with Power Query
Power BI – Connect to your secure API

 

Best Regards
Maggie

 

Community Support Team _ Maggie 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
FabCon Global Hackathon Carousel

FabCon Global Hackathon

Join the Fabric FabCon Global Hackathon—running virtually through Nov 3. Open to all skill levels. $10,000 in prizes!

October Power BI Update Carousel

Power BI Monthly Update - October 2025

Check out the October 2025 Power BI update to learn about new features.

FabCon Atlanta 2026 carousel

FabCon Atlanta 2026

Join us at FabCon Atlanta, March 16-20, for the ultimate Fabric, Power BI, AI and SQL community-led event. Save $200 with code FABCOMM.

Top Kudoed Authors