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! Get ahead of the game and start preparing now! Learn more
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
The Power BI Data Visualization World Championships is back! Get ahead of the game and start preparing now!
| User | Count |
|---|---|
| 19 | |
| 10 | |
| 9 | |
| 8 | |
| 7 |