We have two auth flows in our application, one is a onedrive file picker and the another is aauth flow using msal to login to ms graph API. When I login via ms graph API via msal it works great but it seem to have broken the onedrive picker auth flow.
The error is:
RequestUtils.js:167 Uncaught ClientAuthError: Invalid state. http://localhost:8080_H4WzD, state expected : null.
at ClientAuthError.AuthError [as constructor] (webpack:///./node_modules/msal/lib-es6/error/AuthError.js?:26:28)
at new ClientAuthError (webpack:///./node_modules/msal/lib-es6/error/ClientAuthError.js?:106:28)
at Function.ClientAuthError.createInvalidStateError (webpack:///./node_modules/msal/lib-es6/error/ClientAuthError.js?:136:16)
at Function.RequestUtils.parseLibraryState (webpack:///./node_modules/msal/lib-es6/utils/RequestUtils.js?:167:90)
at UserAgentApplication.getResponseState (webpack:///./node_modules/msal/lib-es6/UserAgentApplication.js?:1148:97)
at new UserAgentApplication (webpack:///./node_modules/msal/lib-es6/UserAgentApplication.js?:127:34)
at eval (webpack:///./src/components/auth-sharepoint/authPopup.js?:22:19)
at Module../src/components/auth-sharepoint/authPopup.js (http://localhost:8080/app.bundle.js:957:1)
at webpack_require (http://localhost:8080/manifest.bundle.js:850:30)
at fn (http://localhost:8080/manifest.bundle.js:152:20)
Current Flow
User can login via msal to download sharepoint files on load via query paremeter link, that loads into babylon js viewer
User can login to onedrive picker SDK and pick the file they want to load into the babylong js viewer, not via the query par.
I've read that they may be incompatable token due to them requesting one from different API's, however I was wondering if I was able to add the token manually and update the endpointHint within the onedrive open config that will allow the flow to use the msal auth.
Anyone got any ideas, any help would be great
thanks
Source
authConfig.js
const msalConfig = {
auth: {
clientId: "id",
authority: "https://login.microsoftonline.com/common",
redirectUri: "http://localhost:8080"
},
cache: {
cacheLocation: "sessionStorage", // This configures where your cache will be stored
storeAuthStateInCookie: false // Set this to "true" if you are having issues on IE11 or Edge
}
};
// Add scopes here for ID token to be used at Microsoft identity platform endpoints.
const loginRequest = {
scopes: ["openid", "profile", "User.Read"]
};
// Add scopes here for access token to be used at Microsoft Graph API endpoints.
const tokenRequest = {
scopes: ["User.Read", "Mail.Read"]
};
module.exports = { msalConfig, loginRequest, tokenRequest };
authPopup.js
import * as Msal from "msal";
import { load3dModel } from "../../index";
import {fetchProgress} from '../../fetch-api-progress';
import { msalConfig, loginRequest, tokenRequest } from "./authConfig";
import { callMSGraph } from "./graph";
import { graphConfig } from "./graphConfig";
const myMSALObj = new Msal.UserAgentApplication(msalConfig);
let username = "";
let encodedString = "";
function handleResponse(resp) {
if (resp !== null) {
username = resp.account.userName
document.getElementById("welcomeMessage").textContent = "Welcome " + username;
getSharedUrl(encodedString);
} else {
// loadPage();
}
}
export const signIn = (encodedStringInput) => {
encodedString = encodedStringInput;
myMSALObj
.loginPopup(loginRequest)
.then(handleResponse)
.catch((error) => {
console.error(error);
});
};
// export const signOut = () => {
// const logoutRequest = {
// account: myMSALObj.getAccountByUsername(username)
// };
// myMSALObj.logout(logoutRequest);
// }
function getTokenPopup(request) {
/**
* See here for more info on account retrieval:
* https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-common/docs/Accounts.md
*/
return myMSALObj.acquireTokenSilent(request).catch((error) => {
console.warn(
"silent token acquisition fails. acquiring token using redirect"
);
if (error instanceof msal.InteractionRequiredAuthError) {
// fallback to interaction when silent call fails
return myMSALObj
.acquireTokenPopup(request)
.then((tokenResponse) => {
return tokenResponse;
})
.catch((error) => {
console.error(error);
});
} else {
console.warn(error);
}
});
}
const getSharedUrl = async () => {
getTokenPopup(loginRequest).then(response => {
const url = `https://graph.microsoft.com/v1.0/shares/u!${encodedString}/driveItem`
callMSGraph(url, response.accessToken, load3dModel, fetchProgress);
}).catch(error => {
console.error(error);
});
};
onedrive.js
function readBlob(blob, callback) {
if (blob) {
let reader = new FileReader();
reader.readAsArrayBuffer(blob);
reader.onload = function (e) {
const arrayBuffer = reader.result;
const blob = new Blob([arrayBuffer], {
type: "text/plain;charset=utf-8"
});
let src = URL.createObjectURL(blob);
callback(src);
};
reader.onerror = function () {
return alert("Failed to load file");
};
}
}
//Reads file from file cloud url and returns blob
async function readCloudFile(res, callback) {
let url = null;
if (res.value.length > 0) {
console.log("res.value", res.value)
url = res.value[0]["@microsoft.graph.downloadUrl"];
}
if (url) {
let response = await fetch(url);
const reader = response.body.getReader();
const contentLength = +response.headers.get('Content-Length');
let receivedLength = 0; // received that many bytes at the moment
let chunks = []; // array of received binary chunks (comprises the body)
while(true) {
const {done, value} = await reader.read();
if (done) {
break;
}
chunks.push(value);
receivedLength += value.length;
let receivedLengthMB = (receivedLength / (1024*1024)).toFixed(2);
let totalLengthMB = (contentLength / (1024*1024)).toFixed(2);
document.getElementById("onedriveLoaderProgress").textContent = `Received ${receivedLengthMB}MB of ${totalLengthMB}MB`
// console.log(`Received ${receivedLengthMB}MB of ${totalLengthMB}MB`)
}
let chunksAll = new Uint8Array(receivedLength); // (4.1)
let position = 0;
for(let chunk of chunks) {
chunksAll.set(chunk, position); // (4.2)
position += chunk.length;
}
let blob = new Blob([chunksAll]);
readBlob(blob, callback);
} else {
alert("File URL not valid");
}
// const length = response.headers.get('Content-Length');
}
//sets up connection with onedrive and opens filepicker, then actions file post-process.
function loadOneDriveConnection(callback) {
if (window.navigator.onLine) {
//App id from Azure App
const oneDriveApplicationId = "id";
//One Drive Picker Options
let odOptions = {
clientId: oneDriveApplicationId,
action: "download",
multiSelect: false,
advanced: {
},
openInNewWindow: false,
success: function (files) {
//On success, load in blob to file reader
readCloudFile(files, callback).catch((err) =>
console.log("Error Reading Cloud File: " + err)
);
},
cancel: function () {
/* cancel handler */
},
error: function (e) {
/* error handler */ alert("OneDrive Error: " + e);
}
};
OneDrive.open(odOptions);
} else {
alert("Application offline, cannot load OneDrive");
}
}
module.exports = { loadOneDriveConnection };
Category
Expected or Desired Behavior
Hi
Library
Description
We have two auth flows in our application, one is a onedrive file picker and the another is aauth flow using msal to login to ms graph API. When I login via ms graph API via msal it works great but it seem to have broken the onedrive picker auth flow.
The error is:
RequestUtils.js:167 Uncaught ClientAuthError: Invalid state. http://localhost:8080_H4WzD, state expected : null. at ClientAuthError.AuthError [as constructor] (webpack:///./node_modules/msal/lib-es6/error/AuthError.js?:26:28) at new ClientAuthError (webpack:///./node_modules/msal/lib-es6/error/ClientAuthError.js?:106:28) at Function.ClientAuthError.createInvalidStateError (webpack:///./node_modules/msal/lib-es6/error/ClientAuthError.js?:136:16) at Function.RequestUtils.parseLibraryState (webpack:///./node_modules/msal/lib-es6/utils/RequestUtils.js?:167:90) at UserAgentApplication.getResponseState (webpack:///./node_modules/msal/lib-es6/UserAgentApplication.js?:1148:97) at new UserAgentApplication (webpack:///./node_modules/msal/lib-es6/UserAgentApplication.js?:127:34) at eval (webpack:///./src/components/auth-sharepoint/authPopup.js?:22:19) at Module../src/components/auth-sharepoint/authPopup.js (http://localhost:8080/app.bundle.js:957:1) at webpack_require (http://localhost:8080/manifest.bundle.js:850:30) at fn (http://localhost:8080/manifest.bundle.js:152:20)
Current Flow
User can login via msal to download sharepoint files on load via query paremeter link, that loads into babylon js viewer User can login to onedrive picker SDK and pick the file they want to load into the babylong js viewer, not via the query par.
I've read that they may be incompatable token due to them requesting one from different API's, however I was wondering if I was able to add the token manually and update the endpointHint within the onedrive open config that will allow the flow to use the msal auth.
Anyone got any ideas, any help would be great
thanks
Source
authConfig.js
authPopup.js
onedrive.js