Join us at FabCon Atlanta from March 16 - 20, 2026, for the ultimate Fabric, Power BI, AI and SQL community-led event. Save $200 with code FABCOMM.
Register now!The Power BI Data Visualization World Championships is back! It's time to submit your entry. Live now!
Hi
I've created a custom data connector using Oauth flow. I'm receiving an error once I select my account to login. Error description below:
"[Invalid Grant] AADB2C90090: The provided JWE is not a valid 5 segment token."
I've tried searching in google and found a few posts but no concrete solution.
Can someone familiar advise what's wrong here and how can I solve it?
Thanks
AfsarP1
Hi @Anonymous
What data source do you connect to?
How do you define the oauth flow in the custom connector?
Here is an example:
Best Regards
Maggie
// This file contains your Data Connector logic
section System;
client_id = Text.FromBinary(Extension.Contents("client_id.txt"));
redirect_uri = "https://ourdomain/oauth2/authresp";
token_uri = "https://ourdomain/oauth2/v2.0/token"; //Used to retrieve an access token
authorize_uri = "https://ourdomain/oauth2/authorize";
logout_uri = "https://login.microsoftonline.com/logout.srf";
// Login modal window dimensions
windowWidth = 720;
windowHeight = 1024;
// OAuth2 scope
scope_prefix = "https://ourdomian.com";
scopes = {
"daily",
"User.Read",
"openid"
//".Read.All",
//"IdentityProvider.Read.All"
//"client_id"
//It can be delegated permission or app permission https://docs.microsoft.com/en-us/graph/auth/auth-concepts#microsoft-graph-permissions
};
[DataSource.Kind="System", Publish="System.Publish"]
shared System.Contents = (url as text) =>
let
source = Json.Document(Web.Contents(url)) //If the data is returned from the datasource in JSON format
in
source;
// Data Source Kind description
System = [
TestConnection = (dataSourcePath) => { "System.Contents", dataSourcePath },
Authentication = [
OAuth = [
StartLogin=StartLogin,
FinishLogin=FinishLogin,
Refresh=Refresh,
Logout=Logout
]
],
Label = Extension.LoadString("DataSourceLabel")
];
// Data Source UI publishing description
System.Publish = [
Beta = true,
Category = "Other",
ButtonText = { Extension.LoadString("ButtonTitle"), Extension.LoadString("ButtonHelp") },
LearnMoreUrl = "https://powerbi.microsoft.com/", //This can be replaced with our System URI. This is a help URI which gives more info about this connector.
SourceImage = System.Icons,
SourceTypeImage = System.Icons
];
//Helper functions for OAuth2: StartLogin, FinishLogin, Refresh, Logout. Start Login definition:
StartLogin = (resourceUrl, state, display) =>
let
authorizeUrl = authorize_uri & "?" & Uri.BuildQueryString([
client_id = client_id,
response_type = "code",
redirect_uri = redirect_uri,
state = state,
scope = "offline_access " & GetScopeString(scopes, scope_prefix) // or GetScopeString(scopes, scope_prefix)
//response_mode = "query",
//login = "login"
])
in
[
LoginUri = authorizeUrl,
CallbackUri = redirect_uri,
WindowHeight = 720,
WindowWidth = 1024,
Context = null
];
//Function that extracts the access_token and other properties related to the OAuth flow.:
FinishLogin = (context, callbackUri, state) =>
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;
//Function that retrieves a new access token from a refresh token.
//Refresh definition:
Refresh = (resourceUrl, refresh_token) => TokenMethod("authorization_code", "code", refresh_token);
//Function that invalidates the user's current access token:
//Logout definition:
Logout = (token) => logout_uri;
//Below definition is to exchange an auth code for an access token:
TokenMethod = (grantType, tokenField, code) =>
let
queryString = [
client_id = client_id,
grant_type = "authorization_code", //grantType, //"authorization_code", //This can also be grant_type
scope = "offline_access " & GetScopeString(scopes, scope_prefix),//Optional
redirect_uri = redirect_uri
//client_id = client_id
],
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;
GetScopeString = (scopes as list, optional scopePrefix as text) as text =>
let
prefix = Value.IfNull(scopePrefix, ""),
addPrefix = List.Transform(scopes, each prefix & _),
asText = Text.Combine(addPrefix, " ")
in
asText;
System.Icons = [
Icon16 = { Extension.Contents("System16.png"), Extension.Contents("System20.png"), Extension.Contents("System24.png"), Extension.Contents("System32.png") },
Icon32 = { Extension.Contents("System32.png"), Extension.Contents("System40.png"), Extension.Contents("System48.png"), Extension.Contents("System64.png") }
];
I'm building this code without the need of Client Secret and I have a client_id.txt file which contains my clientid. I also have the API username and password but cannot figure out how to use it within this code. I've tried using the UsernameLabel and PasswordLabel(https://docs.microsoft.com/en-us/power-query/handlingauthentication)l but the datasource doesn't accept this format.
This is how we used it in our old powershell code:
# Get the bearer token from AAD B2C using ROPC flow
$bearerBody = @{
client_id="xxxxxxxxxxxxxxx"
scope="yyyyyyyyyyyyyyyyyyyyy"
grant_type="password"
response_type="token"
username="abc123"
password="**********"
}
Hi
Does anyone have a suggestion on how to solve this error?
Appreciate your response.
Thanks
AfsarP1
Hi Maggie
I'm building a code to connect to our cloud. I've looked at Jussi's code and also codes from Matt Mason on Github(MyGraph in particular) and built the below code:
// This file contains your Data Connector logic
section System;
client_id = Text.FromBinary(Extension.Contents("client_id.txt"));
redirect_uri = "https://ourdomain/oauth2/authresp";
token_uri = "https://ourdomain/oauth2/v2.0/token"; //Used to retrieve an access token
authorize_uri = "https://ourdomain/oauth2/authorize";
logout_uri = "https://login.microsoftonline.com/logout.srf";
// Login modal window dimensions
windowWidth = 720;
windowHeight = 1024;
// OAuth2 scope
scope_prefix = "https://ourdomian.com";
scopes = {
"daily",
"User.Read",
"openid"
//".Read.All",
//"IdentityProvider.Read.All"
//"client_id"
//It can be delegated permission or app permission https://docs.microsoft.com/en-us/graph/auth/auth-concepts#microsoft-graph-permissions
};
[DataSource.Kind="System", Publish="System.Publish"]
shared System.Contents = (url as text) =>
let
source = Json.Document(Web.Contents(url)) //If the data is returned from the datasource in JSON format
in
source;
// Data Source Kind description
System = [
TestConnection = (dataSourcePath) => { "System.Contents", dataSourcePath },
Authentication = [
OAuth = [
StartLogin=StartLogin,
FinishLogin=FinishLogin,
Refresh=Refresh,
Logout=Logout
]
],
Label = Extension.LoadString("DataSourceLabel")
];
// Data Source UI publishing description
System.Publish = [
Beta = true,
Category = "Other",
ButtonText = { Extension.LoadString("ButtonTitle"), Extension.LoadString("ButtonHelp") },
LearnMoreUrl = "https://powerbi.microsoft.com/", //This can be replaced with our System URI. This is a help URI which gives more info about this connector.
SourceImage = System.Icons,
SourceTypeImage = System.Icons
];
//Helper functions for OAuth2: StartLogin, FinishLogin, Refresh, Logout. Start Login definition:
StartLogin = (resourceUrl, state, display) =>
let
authorizeUrl = authorize_uri & "?" & Uri.BuildQueryString([
client_id = client_id,
response_type = "code",
redirect_uri = redirect_uri,
state = state,
scope = "offline_access " & GetScopeString(scopes, scope_prefix) // or GetScopeString(scopes, scope_prefix)
//response_mode = "query",
//login = "login"
])
in
[
LoginUri = authorizeUrl,
CallbackUri = redirect_uri,
WindowHeight = 720,
WindowWidth = 1024,
Context = null
];
//Function that extracts the access_token and other properties related to the OAuth flow.:
FinishLogin = (context, callbackUri, state) =>
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;
//Function that retrieves a new access token from a refresh token.
//Refresh definition:
Refresh = (resourceUrl, refresh_token) => TokenMethod("authorization_code", "code", refresh_token);
//Function that invalidates the user's current access token:
//Logout definition:
Logout = (token) => logout_uri;
//Below definition is to exchange an auth code for an access token:
TokenMethod = (grantType, tokenField, code) =>
let
queryString = [
client_id = client_id,
grant_type = "authorization_code", //grantType, //"authorization_code", //This can also be grant_type
scope = "offline_access " & GetScopeString(scopes, scope_prefix),//Optional
redirect_uri = redirect_uri
//client_id = client_id
],
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;
GetScopeString = (scopes as list, optional scopePrefix as text) as text =>
let
prefix = Value.IfNull(scopePrefix, ""),
addPrefix = List.Transform(scopes, each prefix & _),
asText = Text.Combine(addPrefix, " ")
in
asText;
System.Icons = [
Icon16 = { Extension.Contents("System16.png"), Extension.Contents("System20.png"), Extension.Contents("System24.png"), Extension.Contents("System32.png") },
Icon32 = { Extension.Contents("System32.png"), Extension.Contents("System40.png"), Extension.Contents("System48.png"), Extension.Contents("System64.png") }
];
I'm building this code without the need of Client Secret and I have a client_id.txt file which contains my clientid. I also have the API username and password but cannot figure out how to use it within this code. I tried using the UsernameLabel and PasswordLabel(https://docs.microsoft.com/en-us/power-query/handlingauthentication)l but the datasource doesn't accept this format.
This is how we used it in our old powershell code:
# Get the bearer token from AAD B2C using ROPC flow
$bearerBody = @{
client_id="xxxxxxxxxxxxxxx"
scope="yyyyyyyyyyyyyyyyyyyyy"
grant_type="password"
response_type="token"
username="abc123"
password="**********"
}
How can modify my code to use the API username and password?
Thanks
AfsarP1
| User | Count |
|---|---|
| 19 | |
| 13 | |
| 9 | |
| 8 | |
| 7 |