Hi @jjkaandorp.
Roger. So the solution from a Power BI custom data connector oAuth implementation with PCKE flow looks like this. If you have any questions or comments, please let me know. Some comments:
- Make sure your auth0 login page supports IE 11
- You need offline enabled for the below to work
Helper variables
client_id = "<AUTH0 CLIENT ID>";
redirect_uri = "https://oauth.powerbi.com/views/oauthredirect.html";
authorize_uri = "https://<YOUR_AUTH_DOMAIN>.com/authorize";
token_uri = "https://<YOUR_AUTH_DOMAIN>.com/oauth/token";
windowWidth = 1200;
windowHeight = 1000;
codeVerifier = Text.NewGuid() & Text.NewGuid();
Start login function
StartLogin = (resourceUrl, state, display) =>
let
params = Json.Document(resourceUrl),
codeChallenge = Base64UrlEncodeWithoutPadding(Crypto.CreateHash(CryptoAlgorithm.SHA256, Text.ToBinary(codeVerifier, TextEncoding.Ascii))),
AuthorizeUrl = authorize_uri & "?" & Uri.BuildQueryString([
client_id = client_id,
scope = "openid offline_access",
response_type = "code",
state = state,
redirect_uri = redirect_uri,
code_challenge_method = "S256",
code_challenge = codeChallenge
])
in
[
LoginUri = AuthorizeUrl,
CallbackUri = redirect_uri,
WindowHeight = windowHeight,
WindowWidth = windowWidth,
Context = []
];
Refresh your token
Refresh = (resourceUrl, refresh_token) =>
let
result = TokenMethod("refresh_token", "refresh_token", refresh_token)
in
result;
Finish login
FinishLogin = (context, callbackUri, state) =>
let
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;
Helper
Base64UrlEncodeWithoutPadding = (hash as binary) as text =>
let
base64Encoded = Binary.ToText(hash, BinaryEncoding.Base64),
base64UrlEncoded = Text.Replace(Text.Replace(base64Encoded, "+", "-"), "/", "_"),
withoutPadding = Text.TrimEnd(base64UrlEncoded, "=")
in
withoutPadding;
TokenMethod
TokenMethod = (grantType, tokenField, code) =>
let
queryString = [
grant_type = grantType,
redirect_uri = redirect_uri,
client_id = client_id,
code_verifier = codeVerifier
],
// hans = Diagnostics.Trace(TraceLevel.Information, "TokenMethod: " & code, code),
queryWithCode = Record.AddField(queryString, tokenField, code),
tokenResponse = Web.Contents(token_uri, [
Content = Text.ToBinary(Uri.BuildQueryString(queryWithCode)),
Headers = [
#"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;