From ccfa7a86d85586c33837f4c2006ba087aae6b5b3 Mon Sep 17 00:00:00 2001 From: Thomas Norling Date: Fri, 21 Nov 2025 16:32:11 -0800 Subject: [PATCH] remove unmaintained samples --- .../ChromiumExtensionSample/README.md | 127 --------- .../ChromiumExtensionSample/auth.js | 212 -------------- .../ChromiumExtensionSample/index.html | 37 --- .../ChromiumExtensionSample/manifest.json | 21 -- .../msal-browser.min.js | 2 - .../VanillaJSTestApp2.0/app/b2c/auth.js | 68 ----- .../VanillaJSTestApp2.0/app/b2c/authConfig.js | 21 -- .../VanillaJSTestApp2.0/app/b2c/index.html | 87 ------ .../VanillaJSTestApp2.0/app/b2c/ui.js | 33 --- .../app/instanceAware/auth.js | 90 ------ .../app/instanceAware/authConfig.js | 61 ---- .../app/instanceAware/graph.js | 78 ------ .../app/instanceAware/index.html | 81 ------ .../app/instanceAware/ui.js | 66 ----- .../app/navigateToLoginPage/auth.js | 90 ------ .../app/navigateToLoginPage/authConfig.js | 58 ---- .../app/navigateToLoginPage/graph.js | 64 ----- .../app/navigateToLoginPage/index.html | 81 ------ .../app/navigateToLoginPage/ui.js | 66 ----- .../app/sample_template/index.html | 66 ----- .../app/sample_template/test/template.spec.ts | 61 ---- .../VanillaJSTestApp2.0/app/ssh/auth.js | 108 ------- .../VanillaJSTestApp2.0/app/ssh/authConfig.js | 58 ---- .../VanillaJSTestApp2.0/app/ssh/index.html | 77 ----- .../VanillaJSTestApp2.0/app/ssh/ui.js | 25 -- .../VanillaJSTestApp2.0/app/ssoSilent/auth.js | 98 ------- .../app/ssoSilent/authConfig.js | 56 ---- .../app/ssoSilent/graph.js | 64 ----- .../app/ssoSilent/index.html | 81 ------ .../VanillaJSTestApp2.0/app/ssoSilent/ui.js | 66 ----- .../app/ssoSilentNoHint/auth.js | 117 -------- .../app/ssoSilentNoHint/authConfig.js | 58 ---- .../app/ssoSilentNoHint/graph.js | 64 ----- .../app/ssoSilentNoHint/index.html | 81 ------ .../app/ssoSilentNoHint/ui.js | 70 ----- .../app/wamBroker/README.md | 10 - .../VanillaJSTestApp2.0/app/wamBroker/auth.js | 78 ------ .../app/wamBroker/authConfig.js | 70 ----- .../app/wamBroker/graph.js | 30 -- .../app/wamBroker/index.html | 78 ------ .../VanillaJSTestApp2.0/app/wamBroker/ui.js | 41 --- .../vue3-sample-app/.npmrc | 1 - .../vue3-sample-app/README.md | 218 --------------- .../vue3-sample-app/index.html | 13 - .../vue3-sample-app/package.json | 22 -- .../vue3-sample-app/public/favicon.ico | Bin 4286 -> 0 bytes .../vue3-sample-app/src/App.vue | 28 -- .../vue3-sample-app/src/assets/logo.png | Bin 6849 -> 0 bytes .../vue3-sample-app/src/authConfig.ts | 52 ---- .../vue3-sample-app/src/components/NavBar.vue | 35 --- .../src/components/SignInButton.vue | 26 -- .../src/components/SignOutButton.vue | 28 -- .../src/components/WelcomeName.vue | 29 -- .../src/composition-api/useIsAuthenticated.ts | 13 - .../src/composition-api/useMsal.ts | 35 --- .../composition-api/useMsalAuthentication.ts | 83 ------ .../vue3-sample-app/src/env.d.ts | 8 - .../vue3-sample-app/src/main.ts | 36 --- .../vue3-sample-app/src/plugins/msalPlugin.ts | 71 ----- .../vue3-sample-app/src/router/Guard.ts | 47 ---- .../src/router/NavigationClient.ts | 31 --- .../vue3-sample-app/src/router/router.ts | 41 --- .../src/utils/MsGraphApiCall.ts | 20 -- .../vue3-sample-app/src/utils/UserInfo.ts | 18 -- .../vue3-sample-app/src/views/Failed.vue | 5 - .../vue3-sample-app/src/views/Home.vue | 19 -- .../vue3-sample-app/src/views/Profile.vue | 52 ---- .../src/views/ProfileNoGuard.vue | 39 --- .../vue3-sample-app/tsconfig.json | 16 -- .../vue3-sample-app/vite.config.ts | 14 - .../ElectronTestApp/.beachballrc | 3 - .../msal-node-samples/ElectronTestApp/.npmrc | 1 - .../ElectronTestApp/README.md | 157 ----------- .../ElectronTestApp/data/cacheTemplate.json | 7 - .../ElectronTestApp/index.html | 64 ----- .../ElectronTestApp/package.json | 29 -- .../ElectronTestApp/playwright.config.ts | 15 - .../ElectronTestApp/src/App.ts | 5 - .../ElectronTestApp/src/AuthCodeListener.ts | 26 -- .../ElectronTestApp/src/AuthProvider.ts | 263 ------------------ .../ElectronTestApp/src/CachePlugin.ts | 52 ---- .../ElectronTestApp/src/Constants.ts | 20 -- .../src/CustomProtocolListener.ts | 50 ---- .../ElectronTestApp/src/FetchManager.ts | 32 --- .../ElectronTestApp/src/GraphReponseTypes.ts | 28 -- .../ElectronTestApp/src/Main.ts | 130 --------- .../ElectronTestApp/src/Renderer.ts | 29 -- .../ElectronTestApp/src/UIManager.ts | 111 -------- .../ElectronTestApp/src/config/AAD.json | 25 -- .../ElectronTestApp/src/config/ADFS.json | 25 -- .../src/config/customConfig.json | 29 -- .../ElectronTestApp/src/preload.ts | 53 ---- .../ElectronTestApp/tsconfig.json | 19 -- .../msal-node-samples/auth-code-pkce/.npmrc | 1 - .../auth-code-pkce/README.md | 51 ---- .../auth-code-pkce/package.json | 28 -- .../auth-code-pkce/src/index.ts | 136 --------- .../auth-code-pkce/src/types/index.ts | 12 - .../auth-code-pkce/tsconfig.json | 16 -- .../msal-node-samples/refresh-token/.npmrc | 1 - .../msal-node-samples/refresh-token/README.md | 150 ---------- .../refresh-token/adalApp.js | 99 ------- .../refresh-token/adalCustomCache.js | 114 -------- .../refresh-token/config/customConfig.json | 9 - .../data/adal.cacheTemplate.json | 16 -- .../data/msal.cacheTemplate.json | 73 ----- .../refresh-token/msalApp.js | 174 ------------ .../refresh-token/msalCachePlugin.js | 52 ---- .../refresh-token/package.json | 24 -- 109 files changed, 5929 deletions(-) delete mode 100644 samples/msal-browser-samples/ChromiumExtensionSample/README.md delete mode 100644 samples/msal-browser-samples/ChromiumExtensionSample/auth.js delete mode 100644 samples/msal-browser-samples/ChromiumExtensionSample/index.html delete mode 100644 samples/msal-browser-samples/ChromiumExtensionSample/manifest.json delete mode 100644 samples/msal-browser-samples/ChromiumExtensionSample/msal-browser.min.js delete mode 100644 samples/msal-browser-samples/VanillaJSTestApp2.0/app/b2c/auth.js delete mode 100644 samples/msal-browser-samples/VanillaJSTestApp2.0/app/b2c/authConfig.js delete mode 100644 samples/msal-browser-samples/VanillaJSTestApp2.0/app/b2c/index.html delete mode 100644 samples/msal-browser-samples/VanillaJSTestApp2.0/app/b2c/ui.js delete mode 100644 samples/msal-browser-samples/VanillaJSTestApp2.0/app/instanceAware/auth.js delete mode 100644 samples/msal-browser-samples/VanillaJSTestApp2.0/app/instanceAware/authConfig.js delete mode 100644 samples/msal-browser-samples/VanillaJSTestApp2.0/app/instanceAware/graph.js delete mode 100644 samples/msal-browser-samples/VanillaJSTestApp2.0/app/instanceAware/index.html delete mode 100644 samples/msal-browser-samples/VanillaJSTestApp2.0/app/instanceAware/ui.js delete mode 100644 samples/msal-browser-samples/VanillaJSTestApp2.0/app/navigateToLoginPage/auth.js delete mode 100644 samples/msal-browser-samples/VanillaJSTestApp2.0/app/navigateToLoginPage/authConfig.js delete mode 100644 samples/msal-browser-samples/VanillaJSTestApp2.0/app/navigateToLoginPage/graph.js delete mode 100644 samples/msal-browser-samples/VanillaJSTestApp2.0/app/navigateToLoginPage/index.html delete mode 100644 samples/msal-browser-samples/VanillaJSTestApp2.0/app/navigateToLoginPage/ui.js delete mode 100644 samples/msal-browser-samples/VanillaJSTestApp2.0/app/sample_template/index.html delete mode 100644 samples/msal-browser-samples/VanillaJSTestApp2.0/app/sample_template/test/template.spec.ts delete mode 100644 samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssh/auth.js delete mode 100644 samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssh/authConfig.js delete mode 100644 samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssh/index.html delete mode 100644 samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssh/ui.js delete mode 100644 samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssoSilent/auth.js delete mode 100644 samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssoSilent/authConfig.js delete mode 100644 samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssoSilent/graph.js delete mode 100644 samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssoSilent/index.html delete mode 100644 samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssoSilent/ui.js delete mode 100644 samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssoSilentNoHint/auth.js delete mode 100644 samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssoSilentNoHint/authConfig.js delete mode 100644 samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssoSilentNoHint/graph.js delete mode 100644 samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssoSilentNoHint/index.html delete mode 100644 samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssoSilentNoHint/ui.js delete mode 100644 samples/msal-browser-samples/VanillaJSTestApp2.0/app/wamBroker/README.md delete mode 100644 samples/msal-browser-samples/VanillaJSTestApp2.0/app/wamBroker/auth.js delete mode 100644 samples/msal-browser-samples/VanillaJSTestApp2.0/app/wamBroker/authConfig.js delete mode 100644 samples/msal-browser-samples/VanillaJSTestApp2.0/app/wamBroker/graph.js delete mode 100644 samples/msal-browser-samples/VanillaJSTestApp2.0/app/wamBroker/index.html delete mode 100644 samples/msal-browser-samples/VanillaJSTestApp2.0/app/wamBroker/ui.js delete mode 100644 samples/msal-browser-samples/vue3-sample-app/.npmrc delete mode 100644 samples/msal-browser-samples/vue3-sample-app/README.md delete mode 100644 samples/msal-browser-samples/vue3-sample-app/index.html delete mode 100644 samples/msal-browser-samples/vue3-sample-app/package.json delete mode 100644 samples/msal-browser-samples/vue3-sample-app/public/favicon.ico delete mode 100644 samples/msal-browser-samples/vue3-sample-app/src/App.vue delete mode 100644 samples/msal-browser-samples/vue3-sample-app/src/assets/logo.png delete mode 100644 samples/msal-browser-samples/vue3-sample-app/src/authConfig.ts delete mode 100644 samples/msal-browser-samples/vue3-sample-app/src/components/NavBar.vue delete mode 100644 samples/msal-browser-samples/vue3-sample-app/src/components/SignInButton.vue delete mode 100644 samples/msal-browser-samples/vue3-sample-app/src/components/SignOutButton.vue delete mode 100644 samples/msal-browser-samples/vue3-sample-app/src/components/WelcomeName.vue delete mode 100644 samples/msal-browser-samples/vue3-sample-app/src/composition-api/useIsAuthenticated.ts delete mode 100644 samples/msal-browser-samples/vue3-sample-app/src/composition-api/useMsal.ts delete mode 100644 samples/msal-browser-samples/vue3-sample-app/src/composition-api/useMsalAuthentication.ts delete mode 100644 samples/msal-browser-samples/vue3-sample-app/src/env.d.ts delete mode 100644 samples/msal-browser-samples/vue3-sample-app/src/main.ts delete mode 100644 samples/msal-browser-samples/vue3-sample-app/src/plugins/msalPlugin.ts delete mode 100644 samples/msal-browser-samples/vue3-sample-app/src/router/Guard.ts delete mode 100644 samples/msal-browser-samples/vue3-sample-app/src/router/NavigationClient.ts delete mode 100644 samples/msal-browser-samples/vue3-sample-app/src/router/router.ts delete mode 100644 samples/msal-browser-samples/vue3-sample-app/src/utils/MsGraphApiCall.ts delete mode 100644 samples/msal-browser-samples/vue3-sample-app/src/utils/UserInfo.ts delete mode 100644 samples/msal-browser-samples/vue3-sample-app/src/views/Failed.vue delete mode 100644 samples/msal-browser-samples/vue3-sample-app/src/views/Home.vue delete mode 100644 samples/msal-browser-samples/vue3-sample-app/src/views/Profile.vue delete mode 100644 samples/msal-browser-samples/vue3-sample-app/src/views/ProfileNoGuard.vue delete mode 100644 samples/msal-browser-samples/vue3-sample-app/tsconfig.json delete mode 100644 samples/msal-browser-samples/vue3-sample-app/vite.config.ts delete mode 100644 samples/msal-node-samples/ElectronTestApp/.beachballrc delete mode 100644 samples/msal-node-samples/ElectronTestApp/.npmrc delete mode 100644 samples/msal-node-samples/ElectronTestApp/README.md delete mode 100644 samples/msal-node-samples/ElectronTestApp/data/cacheTemplate.json delete mode 100644 samples/msal-node-samples/ElectronTestApp/index.html delete mode 100644 samples/msal-node-samples/ElectronTestApp/package.json delete mode 100644 samples/msal-node-samples/ElectronTestApp/playwright.config.ts delete mode 100644 samples/msal-node-samples/ElectronTestApp/src/App.ts delete mode 100644 samples/msal-node-samples/ElectronTestApp/src/AuthCodeListener.ts delete mode 100644 samples/msal-node-samples/ElectronTestApp/src/AuthProvider.ts delete mode 100644 samples/msal-node-samples/ElectronTestApp/src/CachePlugin.ts delete mode 100644 samples/msal-node-samples/ElectronTestApp/src/Constants.ts delete mode 100644 samples/msal-node-samples/ElectronTestApp/src/CustomProtocolListener.ts delete mode 100644 samples/msal-node-samples/ElectronTestApp/src/FetchManager.ts delete mode 100644 samples/msal-node-samples/ElectronTestApp/src/GraphReponseTypes.ts delete mode 100644 samples/msal-node-samples/ElectronTestApp/src/Main.ts delete mode 100644 samples/msal-node-samples/ElectronTestApp/src/Renderer.ts delete mode 100644 samples/msal-node-samples/ElectronTestApp/src/UIManager.ts delete mode 100644 samples/msal-node-samples/ElectronTestApp/src/config/AAD.json delete mode 100644 samples/msal-node-samples/ElectronTestApp/src/config/ADFS.json delete mode 100644 samples/msal-node-samples/ElectronTestApp/src/config/customConfig.json delete mode 100644 samples/msal-node-samples/ElectronTestApp/src/preload.ts delete mode 100644 samples/msal-node-samples/ElectronTestApp/tsconfig.json delete mode 100644 samples/msal-node-samples/auth-code-pkce/.npmrc delete mode 100644 samples/msal-node-samples/auth-code-pkce/README.md delete mode 100644 samples/msal-node-samples/auth-code-pkce/package.json delete mode 100644 samples/msal-node-samples/auth-code-pkce/src/index.ts delete mode 100644 samples/msal-node-samples/auth-code-pkce/src/types/index.ts delete mode 100644 samples/msal-node-samples/auth-code-pkce/tsconfig.json delete mode 100644 samples/msal-node-samples/refresh-token/.npmrc delete mode 100644 samples/msal-node-samples/refresh-token/README.md delete mode 100644 samples/msal-node-samples/refresh-token/adalApp.js delete mode 100644 samples/msal-node-samples/refresh-token/adalCustomCache.js delete mode 100644 samples/msal-node-samples/refresh-token/config/customConfig.json delete mode 100644 samples/msal-node-samples/refresh-token/data/adal.cacheTemplate.json delete mode 100644 samples/msal-node-samples/refresh-token/data/msal.cacheTemplate.json delete mode 100644 samples/msal-node-samples/refresh-token/msalApp.js delete mode 100644 samples/msal-node-samples/refresh-token/msalCachePlugin.js delete mode 100644 samples/msal-node-samples/refresh-token/package.json diff --git a/samples/msal-browser-samples/ChromiumExtensionSample/README.md b/samples/msal-browser-samples/ChromiumExtensionSample/README.md deleted file mode 100644 index c1c58e367a..0000000000 --- a/samples/msal-browser-samples/ChromiumExtensionSample/README.md +++ /dev/null @@ -1,127 +0,0 @@ -# MSAL Browser - Chromium Extension Sample - -This folder contains a sample Chromium extensions demonstrating how to integrate MSAL Browser. - -## Setup - -1. Create a [new app registration](https://docs.microsoft.com/azure/active-directory/develop/quickstart-register-app) in the Microsoft Entra admin center. -1. Provide your client ID in the `PublicClientApplication` configuration in `auth.js`. -1. Under the **Authentication** tab, add a new redirect URI under **Single-page application**. -1. The url of this redirect URI should be of the format `https://.chromiumapp.org`, e.g. `https://epfnbngoodhmbeepjlcohfacgnbhbhah.chromiumapp.org/`. -1. You should also set this url as the **Logout URL**. -1. Your extension ID can be found on the Extensions settings page after the extension has been loaded, or by invoking `chrome.identity.getRedirectURL()` in the extension. - -## Running the extension - -1. On the **Extensions** settings page, click the **Load unpacked** button, and select this folder. -1. The extension will appear in the browser toolbar. -1. **Note:** Because this extension relies on the `chrome.identity` APIs, it will not work in incognito/private browsing. -1. The extension demonstrates how to login, acquire tokens, and logout using MSAL Browser. - -## MSAL Usage - -Chromium extensions are unable to perform certain types of navigation, so applications should leverage the [`chrome.identity.launchWebAuthFlow`](https://developer.chrome.com/apps/identity#method-launchWebAuthFlow) API to perform interactive auth requests. This API takes a url to navigate to, and a callback that will be invoked once the auth flow is completed (which is signaled by Microsoft Entra ID redirecting back to the `chromiumapp.com` url mentioned earlier). Chromium extensions using MSAL Browser can build working auth flows by composing the MSAL `loginRedirect/acquireTokenRedirect` and `handleRedirectPromise` APIs to generate a url and handle the response: - -```js -/** - * Initialize MSAL object - */ -const msalInstance = new msal.PublicClientApplication({ - auth: { - authority: "https://login.microsoftonline.com/common/", - clientId: "your-client-id-here", - redirectUri, - postLogoutRedirectUri: redirectUri, - onRedirectNavigate: (url) => { - resolve(url); - return false; - } - }, - cache: { - cacheLocation: "localStorage" - } -}); - -/** - * Generates a login url - */ -async function getLoginUrl(request) { - return new Promise((resolve, reject) => { - msalInstance.loginRedirect({ - request, - }).catch(reject); - }); -} - - -/** - * Generates an acquire token url - */ -async function getAcquireTokenUrl(request) { - return new Promise((resolve, reject) => { - msalInstance.acquireTokenRedirect({ - request, - }).catch(reject); - }); -} - -/** - * Generates a login url - */ -async function launchWebAuthFlow(url) { - return new Promise((resolve, reject) => { - chrome.identity.launchWebAuthFlow({ - interactive: true, - url - }, (responseUrl) => { - // Response urls includes a hash (login, acquire token calls) - if (responseUrl.includes("#")) { - msalInstance.handleRedirectPromise(`#${responseUrl.split("#")[1]}`) - .then(resolve) - .catch(reject) - } else { - // Logout calls - resolve(); - } - }) - }) -} - -/** - * Generates a logout url - */ -async function getLogoutUrl(request) { - return new Promise((resolve, reject) => { - msalInstance.logout(request).catch(reject); - }); -} - -/** - * Attempts to silent acquire an access token, falling back to interactive. - */ -async function acquireToken(request) { - return msalInstance.acquireTokenSilent(request) - .catch(async (error) => { - console.error(error); - const acquireTokenUrl = await getAcquireTokenUrl(request); - - return launchWebAuthFlow(acquireTokenUrl); - }) -} - -// Login -const loginUrl = await getLoginUrl(); -const loginResult = await launchWebAuthFlow(loginUrl); - -// Acquire token -const { accessToken } = await acquireToken({ - scopes: [ "user.read" ], - account: msalInstance.getAllAccounts()[0] -}); - -// Logout -const logoutUrl = await getLogoutUrl(); -await launchWebAuthFlow(logoutUrl); -``` - - diff --git a/samples/msal-browser-samples/ChromiumExtensionSample/auth.js b/samples/msal-browser-samples/ChromiumExtensionSample/auth.js deleted file mode 100644 index 6d6a38e869..0000000000 --- a/samples/msal-browser-samples/ChromiumExtensionSample/auth.js +++ /dev/null @@ -1,212 +0,0 @@ -// Set the redirect URI to the chromiumapp.com provided by Chromium -const redirectUri = typeof chrome !== "undefined" && chrome.identity ? - chrome.identity.getRedirectURL() : - `${window.location.origin}/index.html`; - -console.log("Chrome extension redirect URI set to ", redirectUri); -console.log("This url must be registered in the Azure portal as a single-page application redirect uri, and as the post logout url"); - -const msalInstance = new msal.PublicClientApplication({ - auth: { - authority: "https://login.microsoftonline.com/common/", - clientId: "your-client-id-here", - redirectUri, - postLogoutRedirectUri: redirectUri, - onRedirectNavigate: (url) => { - resolve(url); - return false; - } - }, - cache: { - cacheLocation: "localStorage" - } -}); - -// Set currently logged in account -const accounts = msalInstance.getAllAccounts(); -if (accounts.length) { - document.getElementById("username").innerHTML = accounts[0].username; -} - -/** - * Adds a sign in button for the user signed into the browser - */ -getSignedInUser() - .then(async (user) => { - if (user) { - const signInHintButton = document.getElementById("sign-in-hint"); - signInHintButton.innerHTML = `Sign In (w/ ${user.email})`; - signInHintButton.addEventListener("click", async () => { - const url = await getLoginUrl({ - loginHint: user.email - }); - - const result = await launchWebAuthFlow(url); - - document.getElementById("username").innerHTML = result.account.username; - }); - signInHintButton.classList.remove("hidden"); - } - }) - -/** - * Sign in button - */ -document.getElementById("sign-in").addEventListener("click", async () => { - const url = await getLoginUrl(); - - const result = await launchWebAuthFlow(url); - - document.getElementById("username").innerHTML = result.account.username; -}); - -/** - * Sign out button - */ -document.getElementById("sign-out").addEventListener("click", async () => { - document.getElementById("username").innerHTML = ""; - document.getElementById("displayname").innerHTML = ""; - - const logoutUrl = await getLogoutUrl(); - - await launchWebAuthFlow(logoutUrl); -}); - -/** - * Call graph button - */ -document.getElementById("call-graph").addEventListener("click", async () => { - const graphResult = await callGraphMeEndpoint(); - - document.getElementById("displayname").innerHTML = graphResult.displayName; -}); - -/** - * Generates a login url - */ -async function getLoginUrl(request, reject) { - return new Promise((resolve) => { - msalInstance.loginRedirect({ - ...request, - onRedirectNavigate: (url) => { - resolve(url); - return false; - } - }).catch(reject); - }); -} - -/** - * Generates a logout url - */ -async function getLogoutUrl(request) { - return new Promise((resolve, reject) => { - msalInstance.logout(request).catch(reject); - }); -} - -/** - * Makes an http request to the MS graph Me endpoint - */ -async function callGraphMeEndpoint() { - const { - accessToken - } = await acquireToken({ - scopes: [ "user.read" ], - account: msalInstance.getAllAccounts()[0] - }); - - return callMSGraph("https://graph.microsoft.com/v1.0/me", accessToken); -} - -/** - * Makes an http request to the given MS graph endpoint - */ -async function callMSGraph(endpoint, accessToken) { - const headers = new Headers(); - const bearer = `Bearer ${accessToken}`; - - headers.append("Authorization", bearer); - - const options = { - method: "GET", - headers - }; - - return fetch(endpoint, options) - .then(response => response.json()) - .catch(error => console.log(error)); -} - -/** - * Attempts to silent acquire an access token, falling back to interactive. - */ -async function acquireToken(request) { - return msalInstance.acquireTokenSilent(request) - .catch(async (error) => { - console.error(error); - const acquireTokenUrl = await getAcquireTokenUrl(request); - - return launchWebAuthFlow(acquireTokenUrl); - }) -} - -/** - * Generates an acquire token url - */ -async function getAcquireTokenUrl(request) { - return new Promise((resolve, reject) => { - msalInstance.acquireTokenRedirect({ - ...request, - onRedirectNavigate: (url) => { - resolve(url); - return false; - } - }).catch(reject); - }); -} - -/** - * Launch the Chromium web auth UI. - * @param {*} url AAD url to navigate to. - * @param {*} interactive Whether or not the flow is interactive - */ -async function launchWebAuthFlow(url) { - return new Promise((resolve, reject) => { - chrome.identity.launchWebAuthFlow({ - interactive: true, - url - }, (responseUrl) => { - // Response urls includes a hash (login, acquire token calls) - if (responseUrl.includes("#")) { - msalInstance.handleRedirectPromise(`#${responseUrl.split("#")[1]}`) - .then(resolve) - .catch(reject) - } else { - // Logout calls - resolve(); - } - }) - }) -} - -/** - * Returns the user sign into the browser. - */ -async function getSignedInUser() { - return new Promise((resolve, reject) => { - if (chrome && chrome.identity) { - // Running in extension popup - chrome.identity.getProfileUserInfo((user) => { - if (user) { - resolve(user); - } else { - resolve(null); - } - }); - } else { - // Running on localhost - resolve(null); - } - }) -} diff --git a/samples/msal-browser-samples/ChromiumExtensionSample/index.html b/samples/msal-browser-samples/ChromiumExtensionSample/index.html deleted file mode 100644 index fc17bc9fb5..0000000000 --- a/samples/msal-browser-samples/ChromiumExtensionSample/index.html +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - MSAL Browser Sample Chromium Extension - - - -
-

Actions

- - - - - -

Signed In User

-
-
Username:
-
- -
Display name:
-
-
-
- - - - diff --git a/samples/msal-browser-samples/ChromiumExtensionSample/manifest.json b/samples/msal-browser-samples/ChromiumExtensionSample/manifest.json deleted file mode 100644 index 9b39471269..0000000000 --- a/samples/msal-browser-samples/ChromiumExtensionSample/manifest.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "$schema": "http://json.schemastore.org/chrome-manifest", - "name": "MSAL Browser Sample Chromium Extension", - "version": "1.0", - "description": "Sample extension demonstrating how to use MSAL Browser", - "manifest_version": 2, - "permissions": [ - "activeTab", - "storage", - "tabs", - "identity", - "identity.email" - ], - "browser_action": { - "default_popup": "index.html" - }, - "web_accessible_resources": [ - "index.html" - ], - "incognito": "not_allowed" - } diff --git a/samples/msal-browser-samples/ChromiumExtensionSample/msal-browser.min.js b/samples/msal-browser-samples/ChromiumExtensionSample/msal-browser.min.js deleted file mode 100644 index 2e509cdd57..0000000000 --- a/samples/msal-browser-samples/ChromiumExtensionSample/msal-browser.min.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! @azure/msal-browser v2.7.0 2020-12-03 */ -"use strict";!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e=e||self).msal={})}(this,function(y){var n=function(e,t){return(n=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)t.hasOwnProperty(r)&&(e[r]=t[r])})(e,t)};function e(e,t){function r(){this.constructor=e}n(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}var h=function(){return(h=Object.assign||function(e){for(var t,r=1,n=arguments.length;ra[0]&&t[1]a[0]&&t[1]=t.length&&e.lastIndexOf(t)===e.length-t.length},$.queryStringToObject=function(e){function t(e){return decodeURIComponent(decodeURIComponent(e.replace(n," ")))}var r,n=/\+/g,o=/([^&=]+)=([^&]*)/g,i={};for(r=o.exec(e);r;)i[t(r[1])]=t(r[2]),r=o.exec(e);return i},$.trimArrayEntries=function(e){return e.map(function(e){return e.trim()})},$.removeEmptyStringsFromArray=function(e){return e.filter(function(e){return!$.isEmpty(e)})},$.jsonParseHelper=function(e){try{return JSON.parse(e)}catch(e){return null}},$);function $(){}var ee,te,re,ne,oe,ie,ae,se,ce,ue,he={LIBRARY_NAME:"MSAL.JS",SKU:"msal.js.common",CACHE_PREFIX:"msal",DEFAULT_AUTHORITY:"https://login.microsoftonline.com/common/",DEFAULT_AUTHORITY_HOST:"login.microsoftonline.com",ADFS:"adfs",AAD_INSTANCE_DISCOVERY_ENDPT:"https://login.microsoftonline.com/common/discovery/instance?api-version=1.1&authorization_endpoint=",RESOURCE_DELIM:"|",NO_ACCOUNT:"NO_ACCOUNT",CLAIMS:"claims",CONSUMER_UTID:"9188040d-6c67-4c5b-b112-36a304b66dad",OPENID_SCOPE:"openid",PROFILE_SCOPE:"profile",OFFLINE_ACCESS_SCOPE:"offline_access",CODE_RESPONSE_TYPE:"code",CODE_GRANT_TYPE:"authorization_code",RT_GRANT_TYPE:"refresh_token",FRAGMENT_RESPONSE_MODE:"fragment",S256_CODE_CHALLENGE_METHOD:"S256",URL_FORM_CONTENT_TYPE:"application/x-www-form-urlencoded;charset=utf-8",AUTHORIZATION_PENDING:"authorization_pending",NOT_DEFINED:"not_defined",EMPTY_STRING:"",FORWARD_SLASH:"/"};(te=ee=ee||{}).CONTENT_TYPE="Content-Type",te.X_CLIENT_CURR_TELEM="x-client-current-telemetry",te.X_CLIENT_LAST_TELEM="x-client-last-telemetry",te.RETRY_AFTER="Retry-After",te.X_MS_LIB_CAPABILITY="x-ms-lib-capability",te.X_MS_LIB_CAPABILITY_VALUE="retry-after, h429",(ne=re=re||{}).ID_TOKEN="idtoken",ne.CLIENT_INFO="client.info",ne.ADAL_ID_TOKEN="adal.idtoken",ne.ERROR="error",ne.ERROR_DESC="error.description",(ie=oe=oe||{}).COMMON="common",ie.ORGANIZATIONS="organizations",ie.CONSUMERS="consumers",(se=ae=ae||{}).CLIENT_ID="client_id",se.REDIRECT_URI="redirect_uri",se.RESPONSE_TYPE="response_type",se.RESPONSE_MODE="response_mode",se.GRANT_TYPE="grant_type",se.CLAIMS="claims",se.SCOPE="scope",se.ERROR="error",se.ERROR_DESCRIPTION="error_description",se.ACCESS_TOKEN="access_token",se.ID_TOKEN="id_token",se.REFRESH_TOKEN="refresh_token",se.EXPIRES_IN="expires_in",se.STATE="state",se.NONCE="nonce",se.PROMPT="prompt",se.SESSION_STATE="session_state",se.CLIENT_INFO="client_info",se.CODE="code",se.CODE_CHALLENGE="code_challenge",se.CODE_CHALLENGE_METHOD="code_challenge_method",se.CODE_VERIFIER="code_verifier",se.CLIENT_REQUEST_ID="client-request-id",se.X_CLIENT_SKU="x-client-SKU",se.X_CLIENT_VER="x-client-VER",se.X_CLIENT_OS="x-client-OS",se.X_CLIENT_CPU="x-client-CPU",se.POST_LOGOUT_URI="post_logout_redirect_uri",se.ID_TOKEN_HINT="id_token_hint",se.DEVICE_CODE="device_code",se.CLIENT_SECRET="client_secret",se.CLIENT_ASSERTION="client_assertion",se.CLIENT_ASSERTION_TYPE="client_assertion_type",se.TOKEN_TYPE="token_type",se.REQ_CNF="req_cnf",se.OBO_ASSERTION="assertion",se.REQUESTED_TOKEN_USE="requested_token_use",se.ON_BEHALF_OF="on_behalf_of",se.FOCI="foci",(ue=ce=ce||{}).ACCESS_TOKEN="access_token",ue.XMS_CC="xms_cc";var de,le,pe={LOGIN:"login",SELECT_ACCOUNT:"select_account",CONSENT:"consent",NONE:"none"};(le=de=de||{}).ACCOUNT="account",le.SID="sid",le.LOGIN_HINT="login_hint",le.ID_TOKEN="id_token",le.DOMAIN_HINT="domain_hint",le.ORGANIZATIONS="organizations",le.CONSUMERS="consumers",le.ACCOUNT_ID="accountIdentifier",le.HOMEACCOUNT_ID="homeAccountIdentifier";de.SID,de.LOGIN_HINT;var fe,ye,ge,me,Ee,ve,Ce,Te,we,Se,Ie,Ae,Re,_e,be={PLAIN:"plain",S256:"S256"};(ye=fe=fe||{}).QUERY="query",ye.FRAGMENT="fragment",ye.FORM_POST="form_post",(me=ge=ge||{}).IMPLICIT_GRANT="implicit",me.AUTHORIZATION_CODE_GRANT="authorization_code",me.CLIENT_CREDENTIALS_GRANT="client_credentials",me.RESOURCE_OWNER_PASSWORD_GRANT="password",me.REFRESH_TOKEN_GRANT="refresh_token",me.DEVICE_CODE_GRANT="device_code",me.JWT_BEARER="urn:ietf:params:oauth:grant-type:jwt-bearer",(ve=Ee=Ee||{}).MSSTS_ACCOUNT_TYPE="MSSTS",ve.ADFS_ACCOUNT_TYPE="ADFS",ve.MSAV1_ACCOUNT_TYPE="MSA",ve.GENERIC_ACCOUNT_TYPE="Generic",(Te=Ce=Ce||{}).CACHE_KEY_SEPARATOR="-",Te.CLIENT_INFO_SEPARATOR=".",(Se=we=we||{}).ID_TOKEN="IdToken",Se.ACCESS_TOKEN="AccessToken",Se.REFRESH_TOKEN="RefreshToken",(Ae=Ie=Ie||{}).ACCOUNT="Account",Ae.CREDENTIAL="Credential",Ae.ID_TOKEN="IdToken",Ae.ACCESS_TOKEN="AccessToken",Ae.REFRESH_TOKEN="RefreshToken",Ae.APP_METADATA="AppMetadata",Ae.TEMPORARY="TempCache",Ae.TELEMETRY="Telemetry",Ae.UNDEFINED="Undefined",Ae.THROTTLING="Throttling",(_e=Re=Re||{})[_e.ADFS=1001]="ADFS",_e[_e.MSA=1002]="MSA",_e[_e.MSSTS=1003]="MSSTS",_e[_e.GENERIC=1004]="GENERIC",_e[_e.ACCESS_TOKEN=2001]="ACCESS_TOKEN",_e[_e.REFRESH_TOKEN=2002]="REFRESH_TOKEN",_e[_e.ID_TOKEN=2003]="ID_TOKEN",_e[_e.APP_METADATA=3001]="APP_METADATA",_e[_e.UNDEFINED=9999]="UNDEFINED";var Oe,ke="appmetadata",Ne="1",Pe={SCHEMA_VERSION:2,MAX_HEADER_BYTES:4e3,CACHE_KEY:"server-telemetry",CATEGORY_SEPARATOR:"|",VALUE_SEPARATOR:",",OVERFLOW_TRUE:"1",OVERFLOW_FALSE:"0",UNKNOWN_ERROR:"unknown_error"};(Oe=y.AuthenticationScheme||(y.AuthenticationScheme={})).POP="pop",Oe.BEARER="Bearer";var Ue,Le,Me,De=60,qe=3600,He="throttling",Ke="invalid_grant",xe="client_mismatch";(Le=Ue=Ue||{}).username="username",Le.password="password",(Me=y.LogLevel||(y.LogLevel={}))[Me.Error=0]="Error",Me[Me.Warning=1]="Warning",Me[Me.Info=2]="Info",Me[Me.Verbose=3]="Verbose";var Fe=(Ge.prototype.logMessage=function(e,t){if(!(t.logLevel>this.level||!this.piiLoggingEnabled&&t.containsPii)){var r=(new Date).toUTCString(),n=(Z.isEmpty(this.correlationId)?"["+r+"] : ":"["+r+"] : ["+this.correlationId+"]")+" : "+this.packageName+"@"+this.packageVersion+" : "+y.LogLevel[t.logLevel]+" - "+e;this.executeCallback(t.logLevel,n,t.containsPii)}},Ge.prototype.executeCallback=function(e,t,r){this.localCallback&&this.localCallback(e,t,r)},Ge.prototype.error=function(e,t){this.logMessage(e,{logLevel:y.LogLevel.Error,containsPii:!1,correlationId:t||""})},Ge.prototype.errorPii=function(e,t){this.logMessage(e,{logLevel:y.LogLevel.Error,containsPii:!0,correlationId:t||""})},Ge.prototype.warning=function(e,t){this.logMessage(e,{logLevel:y.LogLevel.Warning,containsPii:!1,correlationId:t||""})},Ge.prototype.warningPii=function(e,t){this.logMessage(e,{logLevel:y.LogLevel.Warning,containsPii:!0,correlationId:t||""})},Ge.prototype.info=function(e,t){this.logMessage(e,{logLevel:y.LogLevel.Info,containsPii:!1,correlationId:t||""})},Ge.prototype.infoPii=function(e,t){this.logMessage(e,{logLevel:y.LogLevel.Info,containsPii:!0,correlationId:t||""})},Ge.prototype.verbose=function(e,t){this.logMessage(e,{logLevel:y.LogLevel.Verbose,containsPii:!1,correlationId:t||""})},Ge.prototype.verbosePii=function(e,t){this.logMessage(e,{logLevel:y.LogLevel.Verbose,containsPii:!0,correlationId:t||""})},Ge.prototype.isPiiLoggingEnabled=function(){return this.piiLoggingEnabled||!1},Ge);function Ge(e,t,r){this.level=y.LogLevel.Info,e&&(this.localCallback=e.loggerCallback,this.piiLoggingEnabled=e.piiLoggingEnabled,this.level=e.logLevel),this.packageName=t||he.EMPTY_STRING,this.packageVersion=r||he.EMPTY_STRING}var Be="1.7.2",je=(ze.prototype.generateAccountId=function(){return ze.generateAccountIdForCacheKey(this.homeAccountId,this.environment)},ze.prototype.generateCredentialId=function(){return ze.generateCredentialIdForCacheKey(this.credentialType,this.clientId,this.realm,this.familyId)},ze.prototype.generateTarget=function(){return ze.generateTargetForCacheKey(this.target)},ze.prototype.generateCredentialKey=function(){return ze.generateCredentialCacheKey(this.homeAccountId,this.environment,this.credentialType,this.clientId,this.realm,this.target,this.familyId)},ze.prototype.generateType=function(){switch(this.credentialType){case we.ID_TOKEN:return Re.ID_TOKEN;case we.ACCESS_TOKEN:return Re.ACCESS_TOKEN;case we.REFRESH_TOKEN:return Re.REFRESH_TOKEN;default:throw Q.createUnexpectedCredentialTypeError()}},ze.getCredentialType=function(e){return-1!==e.indexOf(we.ACCESS_TOKEN.toLowerCase())?we.ACCESS_TOKEN:-1!==e.indexOf(we.ID_TOKEN.toLowerCase())?we.ID_TOKEN:-1!==e.indexOf(we.REFRESH_TOKEN.toLowerCase())?we.REFRESH_TOKEN:he.NOT_DEFINED},ze.generateCredentialCacheKey=function(e,t,r,n,o,i,a){return[this.generateAccountIdForCacheKey(e,t),this.generateCredentialIdForCacheKey(r,n,o,a),this.generateTargetForCacheKey(i)].join(Ce.CACHE_KEY_SEPARATOR).toLowerCase()},ze.generateAccountIdForCacheKey=function(e,t){return[e,t].join(Ce.CACHE_KEY_SEPARATOR).toLowerCase()},ze.generateCredentialIdForCacheKey=function(e,t,r,n){return[e,e===we.REFRESH_TOKEN&&n||t,r||""].join(Ce.CACHE_KEY_SEPARATOR).toLowerCase()},ze.generateTargetForCacheKey=function(e){return(e||"").toLowerCase()},ze);function ze(){}var We,Ye={code:"redirect_uri_empty",desc:"A redirect URI is required for all calls, and none has been set."},Je={code:"post_logout_uri_empty",desc:"A post logout redirect has not been set."},Ve={code:"claims_request_parsing_error",desc:"Could not parse the given claims request object."},Qe={code:"authority_uri_insecure",desc:"Authority URIs must use https. Please see here for valid authority configuration options: https://docs.microsoft.com/en-us/azure/active-directory/develop/msal-js-initializing-client-applications#configuration-options"},Xe={code:"url_parse_error",desc:"URL could not be parsed into appropriate segments."},Ze={code:"empty_url_error",desc:"URL was empty or null."},$e={code:"empty_input_scopes_error",desc:"Scopes cannot be passed as null, undefined or empty array because they are required to obtain an access token."},et={code:"nonarray_input_scopes_error",desc:"Scopes cannot be passed as non-array."},tt={code:"clientid_input_scopes_error",desc:"Client ID can only be provided as a single scope."},rt={code:"invalid_prompt_value",desc:"Supported prompt values are 'login', 'select_account', 'consent' and 'none'. Please see here for valid configuration options: https://docs.microsoft.com/en-us/azure/active-directory/develop/msal-js-initializing-client-applications#configuration-options"},nt={code:"invalid_claims",desc:"Given claims parameter must be a stringified JSON object."},ot={code:"token_request_empty",desc:"Token request was empty and not found in cache."},it={code:"logout_request_empty",desc:"The logout request was null or undefined."},at={code:"invalid_code_challenge_method",desc:'code_challenge_method passed is invalid. Valid values are "plain" and "S256".'},st={code:"pkce_params_missing",desc:"Both params: code_challenge and code_challenge_method are to be passed if to be sent in the request"},ct={code:"invalid_known_authorities",desc:"knownAuthorities and cloudDiscoveryMetadata cannot both be provided. Please provide cloudDiscoveryMetadata object for AAD, knownAuthorities otherwise."},ut={code:"invalid_cloud_discovery_metadata",desc:"Invalid cloudDiscoveryMetadata provided. Must be a JSON object containing tenant_discovery_endpoint and metadata fields"},ht={code:"untrusted_authority",desc:"The provided authority is not a trusted authority. Please include this authority in the knownAuthorities config parameter."},dt=(t(lt,We=Q),lt.createRedirectUriEmptyError=function(){return new lt(Ye.code,Ye.desc)},lt.createPostLogoutRedirectUriEmptyError=function(){return new lt(Je.code,Je.desc)},lt.createClaimsRequestParsingError=function(e){return new lt(Ve.code,Ve.desc+" Given value: "+e)},lt.createInsecureAuthorityUriError=function(e){return new lt(Qe.code,Qe.desc+" Given URI: "+e)},lt.createUrlParseError=function(e){return new lt(Xe.code,Xe.desc+" Given Error: "+e)},lt.createUrlEmptyError=function(){return new lt(Ze.code,Ze.desc)},lt.createScopesNonArrayError=function(e){return new lt(et.code,et.desc+" Given Scopes: "+e)},lt.createEmptyScopesArrayError=function(e){return new lt($e.code,$e.desc+" Given Scopes: "+e)},lt.createClientIdSingleScopeError=function(e){return new lt(tt.code,tt.desc+" Given Scopes: "+e)},lt.createInvalidPromptError=function(e){return new lt(rt.code,rt.desc+" Given value: "+e)},lt.createInvalidClaimsRequestError=function(){return new lt(nt.code,nt.desc)},lt.createEmptyLogoutRequestError=function(){return new lt(it.code,it.desc)},lt.createEmptyTokenRequestError=function(){return new lt(ot.code,ot.desc)},lt.createInvalidCodeChallengeMethodError=function(){return new lt(at.code,at.desc)},lt.createInvalidCodeChallengeParamsError=function(){return new lt(st.code,st.desc)},lt.createKnownAuthoritiesCloudDiscoveryMetadataError=function(){return new lt(ct.code,ct.desc)},lt.createInvalidCloudDiscoveryMetadataError=function(){return new lt(ut.code,ut.desc)},lt.createUntrustedAuthorityError=function(){return new lt(ht.code,ht.desc)},lt);function lt(e,t){var r=We.call(this,e,t)||this;return r.name="ClientConfigurationError",Object.setPrototypeOf(r,lt.prototype),r}var pt,ft,yt=(gt.fromString=function(e){return new gt((e=e||"").split(" "))},gt.prototype.validateInputScopes=function(e){if(!e||e.length<1)throw dt.createEmptyScopesArrayError(e)},gt.prototype.containsScope=function(e){var t=new gt(this.printScopesLowerCase().split(" "));return!Z.isEmpty(e)&&t.scopes.has(e.toLowerCase())},gt.prototype.containsScopeSet=function(e){var t=this;return!(!e||e.scopes.size<=0)&&this.scopes.size>=e.scopes.size&&e.asArray().every(function(e){return t.containsScope(e)})},gt.prototype.containsOnlyDefaultScopes=function(){var e=0;return this.containsScope(he.OPENID_SCOPE)&&(e+=1),this.containsScope(he.PROFILE_SCOPE)&&(e+=1),this.containsScope(he.OFFLINE_ACCESS_SCOPE)&&(e+=1),this.scopes.size===e},gt.prototype.appendScope=function(e){Z.isEmpty(e)||this.scopes.add(e.trim())},gt.prototype.appendScopes=function(e){var t=this;try{e.forEach(function(e){return t.appendScope(e)})}catch(e){throw Q.createAppendScopeSetError(e)}},gt.prototype.removeScope=function(e){if(Z.isEmpty(e))throw Q.createRemoveEmptyScopeFromSetError(e);this.scopes.delete(e.trim())},gt.prototype.removeDefaultScopes=function(){this.scopes.delete(he.OFFLINE_ACCESS_SCOPE),this.scopes.delete(he.OPENID_SCOPE),this.scopes.delete(he.PROFILE_SCOPE)},gt.prototype.unionScopeSets=function(e){if(!e)throw Q.createEmptyInputScopeSetError(e);var t=new Set;return e.scopes.forEach(function(e){return t.add(e.toLowerCase())}),this.scopes.forEach(function(e){return t.add(e.toLowerCase())}),t},gt.prototype.intersectingScopeSets=function(e){if(!e)throw Q.createEmptyInputScopeSetError(e);var t=this.unionScopeSets(e);e.containsOnlyDefaultScopes()||e.removeDefaultScopes();var r=e.getScopeCount(),n=this.getScopeCount();return t.sizeu?(this.logger.error("Device code expired. Expiration time of device code was "+u),clearInterval(a),i(Q.createDeviceCodeExpiredError()),[3,4]):[3,2];case 2:return t={clientId:this.config.authOptions.clientId,authority:h.authority,scopes:h.scopes},[4,this.executePostToTokenEndpoint(this.authority.tokenEndpoint,s,c,t)];case 3:(r=e.sent()).body&&r.body.error==he.AUTHORIZATION_PENDING?this.logger.info(r.body.error_description):(clearInterval(a),o(r.body)),e.label=4;case 4:return[3,6];case 5:return n=e.sent(),clearInterval(a),i(n),[3,6];case 6:return[2]}})})},t)})]})})},Ur.prototype.createTokenRequestBody=function(e,t){var r=new Qt;r.addScopes(e.scopes),r.addClientId(this.config.authOptions.clientId),r.addGrantType(ge.DEVICE_CODE_GRANT),r.addDeviceCode(t.deviceCode);var n=e.correlationId||this.config.cryptoInterface.createNewGuid();return r.addCorrelationId(n),r.addClientInfo(),(!Z.isEmpty(e.claims)||this.config.authOptions.clientCapabilities&&0>>6):(t<65536?i[a++]=224+(t>>>12):(t<2097152?i[a++]=240+(t>>>18):(t<67108864?i[a++]=248+(t>>>24):(i[a++]=252+(t>>>30),i[a++]=128+(t>>>24&63)),i[a++]=128+(t>>>18&63)),i[a++]=128+(t>>>12&63)),i[a++]=128+(t>>>6&63)),i[a++]=128+(63&t));return i},Sn.stringToArrayBuffer=function(e){for(var t=new ArrayBuffer(e.length),r=new Uint8Array(t),n=0;n>>n&24),2!==n&&e.length-a!=1||(r+=String.fromCharCode(this.uint6ToB64(i>>>18&63),this.uint6ToB64(i>>>12&63),this.uint6ToB64(i>>>6&63),this.uint6ToB64(63&i)),i=0);return 0==t?r:r.substring(0,r.length-t)+(1==t?"=":"==")},An.prototype.uint6ToB64=function(e){return e<26?e+65:e<52?e+71:e<62?e-4:62===e?43:63===e?47:65},An);function An(){}var Rn=(_n.prototype.decode=function(e){var t=e.replace(/-/g,"+").replace(/_/g,"/");switch(t.length%4){case 0:break;case 2:t+="==";break;case 3:t+="=";break;default:throw new Error("Invalid base64 string")}var r=this.base64DecToArr(t);return wn.utf8ArrToString(r)},_n.prototype.base64DecToArr=function(e,t){for(var r=e.replace(/[^A-Za-z0-9\+\/]/g,""),n=r.length,o=t?Math.ceil((3*n+1>>>2)/t)*t:3*n+1>>>2,i=new Uint8Array(o),a=void 0,s=void 0,c=0,u=0,h=0;h>>(16>>>a&24)&255;c=0}return i},_n.prototype.b64ToUint6=function(e){return 64 "+e)},Nn.createBlockReloadInHiddenIframeError=function(){return new Nn(On.blockTokenRequestsInHiddenIframeError.code,On.blockTokenRequestsInHiddenIframeError.desc)},Nn.createIframeClosedPrematurelyError=function(){return new Nn(On.iframeClosedPrematurelyError.code,On.iframeClosedPrematurelyError.desc)},Nn.createSilentSSOInsufficientInfoError=function(){return new Nn(On.silentSSOInsufficientInfoError.code,On.silentSSOInsufficientInfoError.desc)},Nn.createSilentPromptValueError=function(e){return new Nn(On.silentPromptValueError.code,On.silentPromptValueError.desc+" Given value: "+e)},Nn.createTokenRequestCacheError=function(e){return new Nn(On.tokenRequestCacheError.code,On.tokenRequestCacheError.desc+" Error Detail: "+e)},Nn.createInvalidCacheTypeError=function(){return new Nn(On.invalidCacheType.code,""+On.invalidCacheType.desc)},Nn.createNonBrowserEnvironmentError=function(){return new Nn(On.notInBrowserEnvironment.code,On.notInBrowserEnvironment.desc)},Nn);function Nn(e,t){var r=bn.call(this,e,t)||this;return Object.setPrototypeOf(r,Nn.prototype),r.name="BrowserAuthError",r}var Pn=(Un.prototype.generateCodes=function(){return f(this,void 0,void 0,function(){var t,r;return g(this,function(e){switch(e.label){case 0:return t=this.generateCodeVerifier(),[4,this.generateCodeChallengeFromVerifier(t)];case 1:return r=e.sent(),[2,{verifier:t,challenge:r}]}})})},Un.prototype.generateCodeVerifier=function(){try{var e=new Uint8Array(32);return this.cryptoObj.getRandomValues(e),this.base64Encode.urlEncodeArr(e)}catch(e){throw kn.createPkceNotGeneratedError(e)}},Un.prototype.generateCodeChallengeFromVerifier=function(n){return f(this,void 0,void 0,function(){var t,r;return g(this,function(e){switch(e.label){case 0:return e.trys.push([0,2,,3]),[4,this.cryptoObj.sha256Digest(n)];case 1:return t=e.sent(),[2,this.base64Encode.urlEncodeArr(new Uint8Array(t))];case 2:throw r=e.sent(),kn.createPkceNotGeneratedError(r);case 3:return[2]}})})},Un);function Un(e){this.base64Encode=new In,this.cryptoObj=e}var Ln="SHA-256",Mn=new Uint8Array([1,0,1]),Dn=(qn.prototype.sha256Digest=function(r){return f(this,void 0,void 0,function(){var t;return g(this,function(e){return t=wn.stringToUtf8Arr(r),[2,this.hasIECrypto()?this.getMSCryptoDigest(Ln,t):this.getSubtleCryptoDigest(Ln,t)]})})},qn.prototype.getRandomValues=function(e){var t=window.msCrypto||window.crypto;if(!t.getRandomValues)throw kn.createCryptoNotAvailableError("getRandomValues does not exist.");t.getRandomValues(e)},qn.prototype.generateKeyPair=function(t,r){return f(this,void 0,void 0,function(){return g(this,function(e){return[2,this.hasIECrypto()?this.msCryptoGenerateKey(t,r):window.crypto.subtle.generateKey(this._keygenAlgorithmOptions,t,r)]})})},qn.prototype.exportJwk=function(t){return f(this,void 0,void 0,function(){return g(this,function(e){return[2,this.hasIECrypto()?this.msCryptoExportJwk(t):window.crypto.subtle.exportKey(mn,t)]})})},qn.prototype.importJwk=function(n,o,i){return f(this,void 0,void 0,function(){var t,r;return g(this,function(e){return t=qn.getJwkString(n),r=wn.stringToArrayBuffer(t),[2,this.hasIECrypto()?this.msCryptoImportKey(r,o,i):window.crypto.subtle.importKey(mn,n,this._keygenAlgorithmOptions,o,i)]})})},qn.prototype.sign=function(t,r){return f(this,void 0,void 0,function(){return g(this,function(e){return[2,this.hasIECrypto()?this.msCryptoSign(t,r):window.crypto.subtle.sign(this._keygenAlgorithmOptions,t,r)]})})},qn.prototype.hasCryptoAPI=function(){return this.hasIECrypto()||this.hasBrowserCrypto()},qn.prototype.hasIECrypto=function(){return"msCrypto"in window},qn.prototype.hasBrowserCrypto=function(){return"crypto"in window},qn.prototype.getSubtleCryptoDigest=function(t,r){return f(this,void 0,void 0,function(){return g(this,function(e){return[2,window.crypto.subtle.digest(t,r)]})})},qn.prototype.getMSCryptoDigest=function(n,o){return f(this,void 0,void 0,function(){return g(this,function(e){return[2,new Promise(function(t,r){var e=window.msCrypto.subtle.digest(n,o.buffer);e.addEventListener("complete",function(e){t(e.target.result)}),e.addEventListener("error",function(e){r(e)})})]})})},qn.prototype.msCryptoGenerateKey=function(o,i){return f(this,void 0,void 0,function(){var n=this;return g(this,function(e){return[2,new Promise(function(t,r){var e=window.msCrypto.subtle.generateKey(n._keygenAlgorithmOptions,o,i);e.addEventListener("complete",function(e){t(e.target.result)}),e.addEventListener("error",function(e){r(e)})})]})})},qn.prototype.msCryptoExportJwk=function(t){return f(this,void 0,void 0,function(){return g(this,function(e){return[2,new Promise(function(n,o){var e=window.msCrypto.subtle.exportKey(mn,t);e.addEventListener("complete",function(e){var t=e.target.result,r=wn.utf8ArrToString(new Uint8Array(t)).replace(/\r/g,"").replace(/\n/g,"").replace(/\t/g,"").split(" ").join("").replace("\0","");try{n(JSON.parse(r))}catch(e){o(e)}}),e.addEventListener("error",function(e){o(e)})})]})})},qn.prototype.msCryptoImportKey=function(o,i,a){return f(this,void 0,void 0,function(){var n=this;return g(this,function(e){return[2,new Promise(function(t,r){var e=window.msCrypto.subtle.importKey(mn,o,n._keygenAlgorithmOptions,i,a);e.addEventListener("complete",function(e){t(e.target.result)}),e.addEventListener("error",function(e){r(e)})})]})})},qn.prototype.msCryptoSign=function(o,i){return f(this,void 0,void 0,function(){var n=this;return g(this,function(e){return[2,new Promise(function(t,r){var e=window.msCrypto.subtle.sign(n._keygenAlgorithmOptions,o,i);e.addEventListener("complete",function(e){t(e.target.result)}),e.addEventListener("error",function(e){r(e)})})]})})},qn.getJwkString=function(e){return JSON.stringify(e,Object.keys(e).sort())},qn);function qn(){if(!this.hasCryptoAPI())throw kn.createCryptoNotAvailableError("Browser crypto or msCrypto object not available.");this._keygenAlgorithmOptions={name:"RSASSA-PKCS1-v1_5",hash:Ln,modulusLength:2048,publicExponent:Mn}}var Hn=(Kn.prototype.open=function(){return f(this,void 0,void 0,function(){var n=this;return g(this,function(e){return[2,new Promise(function(t,r){var e=window.indexedDB.open(n.dbName,n.version);e.addEventListener("upgradeneeded",function(e){e.target.result.createObjectStore(n.tableName)}),e.addEventListener("success",function(e){n.db=e.target.result,n.dbOpen=!0,t()}),e.addEventListener("error",function(e){return r(e)})})]})})},Kn.prototype.get=function(o){return f(this,void 0,void 0,function(){var n=this;return g(this,function(e){switch(e.label){case 0:return this.dbOpen?[3,2]:[4,this.open()];case 1:e.sent(),e.label=2;case 2:return[2,new Promise(function(t,r){var e=n.db.transaction([n.tableName],"readonly").objectStore(n.tableName).get(o);e.addEventListener("success",function(e){return t(e.target.result)}),e.addEventListener("error",function(e){return r(e)})})]}})})},Kn.prototype.put=function(o,i){return f(this,void 0,void 0,function(){var n=this;return g(this,function(e){switch(e.label){case 0:return this.dbOpen?[3,2]:[4,this.open()];case 1:e.sent(),e.label=2;case 2:return[2,new Promise(function(t,r){var e=n.db.transaction([n.tableName],"readwrite").objectStore(n.tableName).put(i,o);e.addEventListener("success",function(e){return t(e.target.result)}),e.addEventListener("error",function(e){return r(e)})})]}})})},Kn);function Kn(e,t,r){this.dbName=e,this.tableName=t,this.version=r,this.dbOpen=!1}var xn=(Fn.prototype.createNewGuid=function(){return this.guidGenerator.generateGuid()},Fn.prototype.base64Encode=function(e){return this.b64Encode.encode(e)},Fn.prototype.base64Decode=function(e){return this.b64Decode.decode(e)},Fn.prototype.generatePkceCodes=function(){return f(this,void 0,void 0,function(){return g(this,function(e){return[2,this.pkceGenerator.generateCodes()]})})},Fn.prototype.getPublicKeyThumbprint=function(u,h){return f(this,void 0,void 0,function(){var t,r,n,o,i,a,s,c;return g(this,function(e){switch(e.label){case 0:return[4,this.browserCrypto.generateKeyPair(Fn.EXTRACTABLE,Fn.POP_KEY_USAGES)];case 1:return t=e.sent(),[4,this.browserCrypto.exportJwk(t.publicKey)];case 2:return r=e.sent(),n={e:r.e,kty:r.kty,n:r.n},o=Dn.getJwkString(n),[4,this.browserCrypto.sha256Digest(o)];case 3:return i=e.sent(),a=this.b64Encode.urlEncodeArr(new Uint8Array(i)),[4,this.browserCrypto.exportJwk(t.privateKey)];case 4:return s=e.sent(),[4,this.browserCrypto.importJwk(s,!1,["sign"])];case 5:return c=e.sent(),this.cache.put(a,{privateKey:c,publicKey:t.publicKey,requestMethod:u,requestUri:h}),[2,a]}})})},Fn.prototype.signJwt=function(d,l){return f(this,void 0,void 0,function(){var t,r,n,o,i,a,s,c,u,h;return g(this,function(e){switch(e.label){case 0:return[4,this.cache.get(l)];case 1:return t=e.sent(),[4,this.browserCrypto.exportJwk(t.publicKey)];case 2:return r=e.sent(),n=Dn.getJwkString(r),o={alg:r.alg,type:mn},i=this.b64Encode.urlEncode(JSON.stringify(o)),d.cnf={jwk:JSON.parse(n)},a=this.b64Encode.urlEncode(JSON.stringify(d)),s=i+"."+a,c=wn.stringToArrayBuffer(s),[4,this.browserCrypto.sign(t.privateKey,c)];case 3:return u=e.sent(),h=this.b64Encode.urlEncodeArr(new Uint8Array(u)),[2,s+"."+h]}})})},Fn.POP_KEY_USAGES=["sign","verify"],Fn.EXTRACTABLE=!0,Fn.DB_VERSION=1,Fn.TABLE_NAME=(Fn.DB_NAME="msal.db")+".keys",Fn);function Fn(){this.browserCrypto=new Dn,this.b64Encode=new In,this.b64Decode=new Rn,this.guidGenerator=new Cn(this.browserCrypto),this.pkceGenerator=new Pn(this.browserCrypto),this.cache=new Hn(Fn.DB_NAME,Fn.TABLE_NAME,Fn.DB_VERSION)}var Gn,Bn={redirectUriNotSet:{code:"redirect_uri_empty",desc:"A redirect URI is required for all calls, and none has been set."},postLogoutUriNotSet:{code:"post_logout_uri_empty",desc:"A post logout redirect has not been set."},storageNotSupportedError:{code:"storage_not_supported",desc:"Given storage configuration option was not supported."},noRedirectCallbacksSet:{code:"no_redirect_callbacks",desc:"No redirect callbacks have been set. Please call setRedirectCallbacks() with the appropriate function arguments before continuing. More information is available here: https://github.com/AzureAD/microsoft-authentication-library-for-js/wiki/MSAL-basics."},invalidCallbackObject:{code:"invalid_callback_object",desc:"The object passed for the callback was invalid. More information is available here: https://github.com/AzureAD/microsoft-authentication-library-for-js/wiki/MSAL-basics."},stubPcaInstanceCalled:{code:"stubbed_public_client_application_called",desc:"Stub instance of Public Client Application was called. If using msal-react, please ensure context is not used without a provider."},inMemRedirectUnavailable:{code:"in_mem_redirect_unavailable",desc:"Redirect cannot be supported. In-memory storage was selected and storeAuthStateInCookie=false, which would cause the library to be unable to handle the incoming hash. If you would like to use the redirect API, please use session/localStorage or set storeAuthStateInCookie=true."}},jn=(e(zn,Gn=c),zn.createRedirectUriEmptyError=function(){return new zn(Bn.redirectUriNotSet.code,Bn.redirectUriNotSet.desc)},zn.createPostLogoutRedirectUriEmptyError=function(){return new zn(Bn.postLogoutUriNotSet.code,Bn.postLogoutUriNotSet.desc)},zn.createStorageNotSupportedError=function(e){return new zn(Bn.storageNotSupportedError.code,Bn.storageNotSupportedError.desc+" Given Location: "+e)},zn.createInvalidCallbackObjectError=function(e){return new zn(Bn.invalidCallbackObject.code,Bn.invalidCallbackObject.desc+" Given value for callback function: "+e)},zn.createRedirectCallbacksNotSetError=function(){return new zn(Bn.noRedirectCallbacksSet.code,Bn.noRedirectCallbacksSet.desc)},zn.createStubPcaInstanceCalledError=function(){return new zn(Bn.stubPcaInstanceCalled.code,Bn.stubPcaInstanceCalled.desc)},zn.createInMemoryRedirectUnavailableError=function(){return new zn(Bn.inMemRedirectUnavailable.code,Bn.inMemRedirectUnavailable.desc)},zn);function zn(e,t){var r=Gn.call(this,e,t)||this;return r.name="BrowserConfigurationAuthError",Object.setPrototypeOf(r,zn.prototype),r}var Wn=(Object.defineProperty(Yn.prototype,"windowStorage",{get:function(){return this._windowStorage||(this._windowStorage=window[this.cacheLocation]),this._windowStorage},enumerable:!0,configurable:!0}),Yn.prototype.validateWindowStorage=function(e){if(e!==y.BrowserCacheLocation.LocalStorage&&e!==y.BrowserCacheLocation.SessionStorage)throw jn.createStorageNotSupportedError(e);if(!window[e])throw jn.createStorageNotSupportedError(e)},Yn.prototype.getItem=function(e){return this.windowStorage.getItem(e)},Yn.prototype.setItem=function(e,t){this.windowStorage.setItem(e,t)},Yn.prototype.removeItem=function(e){this.windowStorage.removeItem(e)},Yn.prototype.getKeys=function(){return Object.keys(this.windowStorage)},Yn.prototype.containsKey=function(e){return this.windowStorage.hasOwnProperty(e)},Yn);function Yn(e){this.validateWindowStorage(e),this.cacheLocation=e}var Jn=(Vn.prototype.getItem=function(e){return this.cache.get(e)||null},Vn.prototype.setItem=function(e,t){this.cache.set(e,t)},Vn.prototype.removeItem=function(e){this.cache.delete(e)},Vn.prototype.getKeys=function(){var r=[];return this.cache.forEach(function(e,t){r.push(t)}),r},Vn.prototype.containsKey=function(e){return this.cache.has(e)},Vn);function Vn(){this.cache=new Map}var Qn,Xn=(e(Zn,Qn=_t),Zn.prototype.setupBrowserStorage=function(e){switch(e){case y.BrowserCacheLocation.LocalStorage:case y.BrowserCacheLocation.SessionStorage:try{return new Wn(e)}catch(e){return this.logger.verbose(e),this.cacheConfig.cacheLocation=y.BrowserCacheLocation.MemoryStorage,new Jn}case y.BrowserCacheLocation.MemoryStorage:default:return new Jn}},Zn.prototype.migrateCacheEntries=function(){var r=this,e=he.CACHE_PREFIX+"."+re.ID_TOKEN,t=he.CACHE_PREFIX+"."+re.CLIENT_INFO,n=he.CACHE_PREFIX+"."+re.ERROR,o=he.CACHE_PREFIX+"."+re.ERROR_DESC,i=[this.browserStorage.getItem(e),this.browserStorage.getItem(t),this.browserStorage.getItem(n),this.browserStorage.getItem(o)];[re.ID_TOKEN,re.CLIENT_INFO,re.ERROR,re.ERROR_DESC].forEach(function(e,t){return r.migrateCacheEntry(e,i[t])})},Zn.prototype.migrateCacheEntry=function(e,t){t&&this.setTemporaryCache(e,t,!0)},Zn.prototype.validateAndParseJson=function(e){try{var t=JSON.parse(e);return t&&"object"==typeof t?t:null}catch(e){return null}},Zn.prototype.getItem=function(e){return this.browserStorage.getItem(e)},Zn.prototype.setItem=function(e,t){this.browserStorage.setItem(e,t)},Zn.prototype.getAccount=function(e){var t=this.getItem(e);if(Z.isEmpty(t))return null;var r=this.validateAndParseJson(t),n=_t.toObject(new At,r);return At.isAccountEntity(n)?n:null},Zn.prototype.setAccount=function(e){var t=e.generateAccountKey();this.setItem(t,JSON.stringify(e))},Zn.prototype.getIdTokenCredential=function(e){var t=this.getItem(e);if(Z.isEmpty(t))return null;var r=this.validateAndParseJson(t),n=_t.toObject(new nr,r);return nr.isIdTokenEntity(n)?n:null},Zn.prototype.setIdTokenCredential=function(e){var t=e.generateCredentialKey();this.setItem(t,JSON.stringify(e))},Zn.prototype.getAccessTokenCredential=function(e){var t=this.getItem(e);if(Z.isEmpty(t))return null;var r=this.validateAndParseJson(t),n=_t.toObject(new ar,r);return ar.isAccessTokenEntity(n)?n:null},Zn.prototype.setAccessTokenCredential=function(e){var t=e.generateCredentialKey();this.setItem(t,JSON.stringify(e))},Zn.prototype.getRefreshTokenCredential=function(e){var t=this.getItem(e);if(Z.isEmpty(t))return null;var r=this.validateAndParseJson(t),n=_t.toObject(new ur,r);return ur.isRefreshTokenEntity(n)?n:null},Zn.prototype.setRefreshTokenCredential=function(e){var t=e.generateCredentialKey();this.setItem(t,JSON.stringify(e))},Zn.prototype.getAppMetadata=function(e){var t=this.getItem(e);if(Z.isEmpty(t))return null;var r=this.validateAndParseJson(t),n=_t.toObject(new Sr,r);return Sr.isAppMetadataEntity(e,n)?n:null},Zn.prototype.setAppMetadata=function(e){var t=e.generateAppMetadataKey();this.setItem(t,JSON.stringify(e))},Zn.prototype.getServerTelemetry=function(e){var t=this.getItem(e);if(Z.isEmpty(t))return null;var r=this.validateAndParseJson(t),n=_t.toObject(new Jr,r);return Jr.isServerTelemetryEntity(e,n)?n:null},Zn.prototype.setServerTelemetry=function(e,t){this.setItem(e,JSON.stringify(t))},Zn.prototype.getThrottlingCache=function(e){var t=this.getItem(e);if(Z.isEmpty(t))return null;var r=this.validateAndParseJson(t),n=_t.toObject(new Qr,r);return Qr.isThrottlingEntity(e,n)?n:null},Zn.prototype.setThrottlingCache=function(e,t){this.setItem(e,JSON.stringify(t))},Zn.prototype.getTemporaryCache=function(e,t){var r=t?this.generateCacheKey(e):e;if(this.cacheConfig.storeAuthStateInCookie){var n=this.getItemCookie(r);if(n)return n}var o=this.getItem(r);return Z.isEmpty(o)?null:o},Zn.prototype.setTemporaryCache=function(e,t,r){var n=r?this.generateCacheKey(e):e;this.setItem(n,t),this.cacheConfig.storeAuthStateInCookie&&this.setItemCookie(n,t)},Zn.prototype.removeItem=function(e){return this.browserStorage.removeItem(e),this.cacheConfig.storeAuthStateInCookie&&this.clearItemCookie(e),!0},Zn.prototype.containsKey=function(e){return this.browserStorage.containsKey(e)},Zn.prototype.getKeys=function(){return this.browserStorage.getKeys()},Zn.prototype.clear=function(){var t=this;this.removeAllAccounts(),this.removeAppMetadata(),this.browserStorage.getKeys().forEach(function(e){!t.browserStorage.containsKey(e)||-1===e.indexOf(he.CACHE_PREFIX)&&-1===e.indexOf(t.clientId)||t.removeItem(e)})},Zn.prototype.setItemCookie=function(e,t,r){var n=encodeURIComponent(e)+"="+encodeURIComponent(t)+";path=/;";r&&(n+="expires="+this.getCookieExpirationTime(r)+";"),document.cookie=n},Zn.prototype.getItemCookie=function(e){for(var t=encodeURIComponent(e)+"=",r=document.cookie.split(";"),n=0;no)return s.removeHiddenIframe(a),clearInterval(i),void n(kn.createMonitorIframeTimeoutError());var e;try{e=a.contentWindow.location.href}catch(e){}if(!Z.isEmpty(e)){var t=a.contentWindow.location.hash;return mt.hashContainsKnownProperties(t)?(s.removeHiddenIframe(a),clearInterval(i),void r(t)):void 0}},fn)})},Co.prototype.loadFrame=function(n){var o=this;return new Promise(function(e,t){var r=o.createHiddenIframe();setTimeout(function(){r?(r.src=n,e(r)):t("Unable to load iframe")},o.navigateFrameWait)})},Co.prototype.loadFrameSync=function(e){var t=this.createHiddenIframe();return t.src=e,t},Co.prototype.createHiddenIframe=function(){var e=document.createElement("iframe");return e.style.visibility="hidden",e.style.position="absolute",e.style.width=e.style.height="0",e.style.border="0",e.setAttribute("sandbox","allow-scripts allow-same-origin allow-forms"),document.getElementsByTagName("body")[0].appendChild(e),e},Co.prototype.removeHiddenIframe=function(e){document.body===e.parentNode&&document.body.removeChild(e)},Co);function Co(e,t,r){var n=Eo.call(this,e,t)||this;return n.navigateFrameWait=r,n}var To;(To=y.EventType||(y.EventType={})).LOGIN_START="msal:loginStart",To.LOGIN_SUCCESS="msal:loginSuccess",To.LOGIN_FAILURE="msal:loginFailure",To.ACQUIRE_TOKEN_START="msal:acquireTokenStart",To.ACQUIRE_TOKEN_SUCCESS="msal:acquireTokenSuccess",To.ACQUIRE_TOKEN_FAILURE="msal:acquireTokenFailure",To.ACQUIRE_TOKEN_NETWORK_START="msal:acquireTokenFromNetworkStart",To.SSO_SILENT_START="msal:ssoSilentStart",To.SSO_SILENT_SUCCESS="msal:ssoSilentSuccess",To.SSO_SILENT_FAILURE="msal:ssoSilentFailure",To.HANDLE_REDIRECT_START="msal:handleRedirectStart",To.HANDLE_REDIRECT_END="msal:handleRedirectEnd",To.LOGOUT_START="msal:logoutStart",To.LOGOUT_SUCCESS="msal:logoutSuccess",To.LOGOUT_FAILURE="msal:logoutFailure";var wo=(So.prototype.handleRedirectPromise=function(n){return f(this,void 0,void 0,function(){var t,r=this;return g(this,function(e){return this.emitEvent(y.EventType.HANDLE_REDIRECT_START,y.InteractionType.Redirect),t=this.getAllAccounts(),this.isBrowserEnvironment?[2,this.handleRedirectResponse(n).then(function(e){return e&&(t.length { - myMSALObj.handleRedirectPromise().then(response => { - if (response) { - handleResponse(response); - } - }).catch(error => { - console.log(error); - }); -}); - -function handleResponse(response) { - if (response !== null) { - accountId = response.account.homeAccountId; - showWelcomeMessage(response.account); - updateUI(response); - } -} - -const currentAccounts = myMSALObj.getAllAccounts(); -if (currentAccounts.length > 1) { - // Add choose account code here -} else if (currentAccounts.length === 1) { - accountId = currentAccounts[0].homeAccountId; - showWelcomeMessage(currentAccounts[0]); -} - -async function signIn(method) { - if (method === "loginPopup") { - await myMSALObj.loginPopup().then(handleResponse).catch(function (error) { - console.log(error); - }); - } else if (method === "loginRedirect") { - myMSALObj.loginRedirect(); - } -} - -function signOut() { - const currentAcc = myMSALObj.getAccount({accountId}) - myMSALObj.logout(currentAcc); -} - -function getAccessTokenPopup() { - request = tokenRequest; - myMSALObj.acquireTokenPopup(request).then(handleResponse).catch(error => { - console.log(error); - }); -} - -function getAccessTokenRedirect() { - request = tokenRequest; - myMSALObj.acquireTokenRedirect(request); -} - -function getAccessTokenSilent() { - request = tokenRequest - request.account = myMSALObj.getAccount({accountId}); - myMSALObj.acquireTokenSilent(request).then(handleResponse).catch(error => { - console.log(error); - }) -} \ No newline at end of file diff --git a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/b2c/authConfig.js b/samples/msal-browser-samples/VanillaJSTestApp2.0/app/b2c/authConfig.js deleted file mode 100644 index 8519ce2097..0000000000 --- a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/b2c/authConfig.js +++ /dev/null @@ -1,21 +0,0 @@ -// Config object to be passed to Msal on creation -const msalConfig = { - auth: { - clientId: "4c837770-7a2b-471e-aafa-3328d04a23b1", - authority: "https://msidlabb2c.b2clogin.com/msidlabb2c.onmicrosoft.com/B2C_1_SISOPolicy/", - knownAuthorities: ["msidlabb2c.b2clogin.com"] - }, - 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 - }, - system: { - allowPlatformBroker: false // Disables WAM Broker - } -}; - -// Add here scopes for id token to be used at MS Identity Platform endpoints. -const tokenRequest = { - scopes: ["https://msidlabb2c.onmicrosoft.com/4c837770-7a2b-471e-aafa-3328d04a23b1/read "], - forceRefresh: false // Set this to "true" to skip a cached token and go to the server to get a new token -}; diff --git a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/b2c/index.html b/samples/msal-browser-samples/VanillaJSTestApp2.0/app/b2c/index.html deleted file mode 100644 index 86dfc377d0..0000000000 --- a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/b2c/index.html +++ /dev/null @@ -1,87 +0,0 @@ - - - - - - - Quickstart | MSAL.JS Vanilla JavaScript SPA - - - - - - - - - - - -
-
Vanilla JavaScript SPA calling MS Graph API with MSAL.JS
-
-
- -
-
-
-
-
-
-
- -
-
-
-
- - - - - - - - - - - - - \ No newline at end of file diff --git a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/b2c/ui.js b/samples/msal-browser-samples/VanillaJSTestApp2.0/app/b2c/ui.js deleted file mode 100644 index a6af5fa69f..0000000000 --- a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/b2c/ui.js +++ /dev/null @@ -1,33 +0,0 @@ -// Select DOM elements to work with -const welcomeDiv = document.getElementById("WelcomeMessage"); -const signInButton = document.getElementById("SignIn"); -const cardDiv = document.getElementById("card-div"); -const accessTokenButtonRedirect = document.getElementById("getAccessTokenRedirect"); -const accessTokenButtonPopup = document.getElementById("getAccessTokenPopup"); -const accessTokenButtonSilent = document.getElementById("getAccessTokenSilent"); -const profileDiv = document.getElementById("profile-div"); - -function showWelcomeMessage(account) { - // Reconfiguring DOM elements - cardDiv.style.display = 'initial'; - welcomeDiv.innerHTML = `Welcome ${account.name}`; - signInButton.nextElementSibling.style.display = 'none'; - signInButton.setAttribute("onclick", "signOut();"); - signInButton.setAttribute('class', "btn btn-success") - signInButton.innerHTML = "Sign Out"; -} - -function updateUI(response) { - const oldAccessTokenDiv = document.getElementById('access-token-info'); - if (oldAccessTokenDiv) { - oldAccessTokenDiv.remove(); - } - const accessTokenDiv = document.createElement('div'); - accessTokenDiv.id = "access-token-info"; - profileDiv.appendChild(accessTokenDiv); - - const scopes = document.createElement('p'); - scopes.innerHTML = "Access Token Acquired for Scopes: " + response.scopes; - - accessTokenDiv.appendChild(scopes); -} \ No newline at end of file diff --git a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/instanceAware/auth.js b/samples/msal-browser-samples/VanillaJSTestApp2.0/app/instanceAware/auth.js deleted file mode 100644 index d52535e3f0..0000000000 --- a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/instanceAware/auth.js +++ /dev/null @@ -1,90 +0,0 @@ -// Browser check variables -// If you support IE, our recommendation is that you sign-in using Redirect APIs -// If you as a developer are testing using Edge InPrivate mode, please add "isEdge" to the if check -const ua = window.navigator.userAgent; -const msie = ua.indexOf("MSIE "); -const msie11 = ua.indexOf("Trident/"); -const msedge = ua.indexOf("Edge/"); -const isIE = msie > 0 || msie11 > 0; -const isEdge = msedge > 0; - -let signInType; -let accountId = ""; - -// Create the main myMSALObj instance -// configuration parameters are located at authConfig.js -const myMSALObj = new msal.PublicClientApplication(msalConfig); - -// Redirect: once login is successful and redirects with tokens, call Graph API -myMSALObj.initialize().then(() => { - myMSALObj.handleRedirectPromise().then(handleResponse).catch(err => { - console.error(err); - }); -}); - -function handleResponse(resp) { - if (resp !== null) { - accountId = resp.account.homeAccountId; - showWelcomeMessage(resp.account); - } else { - // need to call getAccount here? - const currentAccounts = myMSALObj.getAllAccounts(); - if (!currentAccounts || currentAccounts.length < 1) { - return; - } else if (currentAccounts.length > 1) { - // Add choose account code here - } else if (currentAccounts.length === 1) { - accountId = currentAccounts[0].homeAccountId; - showWelcomeMessage(currentAccounts[0]); - } - } -} - -async function signIn(method) { - signInType = isIE ? "loginRedirect" : method; - if (signInType === "loginPopup") { - return myMSALObj.loginPopup(loginRequest).then(handleResponse).catch(function (error) { - console.log(error); - }); - } else if (signInType === "loginRedirect") { - return myMSALObj.loginRedirect(loginRequest) - } -} - -function signOut() { - const logoutRequest = { - account: myMSALObj.getAccount({accountId}) - }; - - myMSALObj.logoutRedirect(logoutRequest); -} - -async function getTokenPopup(request, account) { - request.account = account; - return await myMSALObj.acquireTokenSilent(request).catch(async (error) => { - console.log("silent token acquisition fails."); - if (error instanceof msal.InteractionRequiredAuthError) { - console.log("acquiring token using popup"); - return myMSALObj.acquireTokenPopup(request).catch(error => { - console.error(error); - }); - } else { - console.error(error); - } - }); -} - -// This function can be removed if you do not need to support IE -async function getTokenRedirect(request, account) { - request.account = account; - return await myMSALObj.acquireTokenSilent(request).catch(async (error) => { - console.log("silent token acquisition fails."); - if (error instanceof msal.InteractionRequiredAuthError) { - // fallback to interaction when silent call fails - console.log("acquiring token using redirect"); - myMSALObj.acquireTokenRedirect(request); - } else { - console.error(error); - } - }); -} diff --git a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/instanceAware/authConfig.js b/samples/msal-browser-samples/VanillaJSTestApp2.0/app/instanceAware/authConfig.js deleted file mode 100644 index 6159569f26..0000000000 --- a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/instanceAware/authConfig.js +++ /dev/null @@ -1,61 +0,0 @@ -// Config object to be passed to Msal on creation -const msalConfig = { - auth: { - clientId: "b5c2e510-4a17-4feb-b219-e55aa5b74144", - authority: "https://login.microsoftonline.com/common" - }, - 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 - }, - system: { - allowPlatformBroker: false, // Disables WAM Broker - loggerOptions: { - loggerCallback: (level, message, containsPii) => { - if (containsPii) { - return; - } - switch (level) { - case msal.LogLevel.Error: - console.error(message); - return; - case msal.LogLevel.Info: - console.info(message); - return; - case msal.LogLevel.Verbose: - console.debug(message); - return; - case msal.LogLevel.Warning: - console.warn(message); - return; - } - } - } - } -}; - -// Add here scopes for id token to be used at MS Identity Platform endpoints. -const loginRequest = { - scopes: ["User.Read"], - extraQueryParameters: { - "instance_aware": "true" - } -}; - -// Add here scopes for access token to be used at MS Graph API endpoints. -const tokenRequest = { - scopes: ["Mail.Read"], - forceRefresh: false, // Set this to "true" to skip a cached token and go to the server to get a new token - extraQueryParameters: { - "instance_aware": "true" - } -}; - -const silentRequest = { - scopes: ["openid", "profile", "User.Read", "Mail.Read"], - extraQueryParameters: { - "instance_aware": "true" - } -}; - -const logoutRequest = {} diff --git a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/instanceAware/graph.js b/samples/msal-browser-samples/VanillaJSTestApp2.0/app/instanceAware/graph.js deleted file mode 100644 index 63466f73f7..0000000000 --- a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/instanceAware/graph.js +++ /dev/null @@ -1,78 +0,0 @@ -// Helper function to call MS Graph API endpoint -// using authorization bearer token scheme -function callMSGraph(endpoint, accessToken, callback) { - const headers = new Headers(); - const bearer = `Bearer ${accessToken}`; - - headers.append("Authorization", bearer); - - const options = { - method: "GET", - headers: headers - }; - - console.log('request made to Graph API at: ' + new Date().toString()); - - fetch(endpoint, options) - .then(response => response.json()) - .then(response => callback(response, endpoint)) - .catch(error => console.log(error)); -} - -function getGraphMeEndpoint(msGraphHost) { - if (!msGraphHost) { - return "https://graph.microsoft-ppe.com/v1.0/me"; - } - return `https://${msGraphHost}/v1.0/me` -} - -function getGraphMailEndpoint(msGraphHost) { - if (!msGraphHost) { - return "https://graph.microsoft-ppe.com/v1.0/me/messages"; - } - return `https://${msGraphHost}/v1.0/me/messages` -} - -async function seeProfile() { - const currentAcc = myMSALObj.getAccount({accountId}); - if (currentAcc) { - const response = await getTokenPopup(loginRequest, currentAcc).catch(error => { - console.log(error); - }); - callMSGraph(getGraphMeEndpoint(response.msGraphHost), response.accessToken, updateUI); - profileButton.style.display = 'none'; - } -} - -async function readMail() { - const currentAcc = myMSALObj.getAccount({accountId}); - if (currentAcc) { - const response = await getTokenPopup(tokenRequest, currentAcc).catch(error => { - console.log(error); - }); - callMSGraph(getGraphMailEndpoint(response.msGraphHost), response.accessToken, updateUI); - mailButton.style.display = 'none'; - } -} - -async function seeProfileRedirect() { - const currentAcc = myMSALObj.getAccount({accountId}); - if (currentAcc) { - const response = await getTokenRedirect(loginRequest, currentAcc).catch(error => { - console.log(error); - }); - callMSGraph(getGraphMeEndpoint(response.msGraphHost), response.accessToken, updateUI); - profileButton.style.display = 'none'; - } -} - -async function readMailRedirect() { - const currentAcc = myMSALObj.getAccount({accountId}); - if (currentAcc) { - const response = await getTokenRedirect(tokenRequest, currentAcc).catch(error => { - console.log(error); - }); - callMSGraph(getGraphMailEndpoint(response.msGraphHost), response.accessToken, updateUI); - mailButton.style.display = 'none'; - } -} diff --git a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/instanceAware/index.html b/samples/msal-browser-samples/VanillaJSTestApp2.0/app/instanceAware/index.html deleted file mode 100644 index d79b90dafb..0000000000 --- a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/instanceAware/index.html +++ /dev/null @@ -1,81 +0,0 @@ - - - - - - - Quickstart | MSAL.JS Vanilla JavaScript SPA - - - - - - - - - - -
-
Vanilla JavaScript SPA calling MS Graph API with MSAL.JS
-
-
- -
-
-
-
-
-
-
- -
-
-
-
- - - - - - - - - - - - - - \ No newline at end of file diff --git a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/instanceAware/ui.js b/samples/msal-browser-samples/VanillaJSTestApp2.0/app/instanceAware/ui.js deleted file mode 100644 index 8c949791d7..0000000000 --- a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/instanceAware/ui.js +++ /dev/null @@ -1,66 +0,0 @@ -// Select DOM elements to work with -const welcomeDiv = document.getElementById("WelcomeMessage"); -const signInButton = document.getElementById("SignIn"); -const cardDiv = document.getElementById("card-div"); -const mailButton = document.getElementById("readMail"); -const profileButton = document.getElementById("seeProfile"); -const profileDiv = document.getElementById("profile-div"); - -function showWelcomeMessage(account) { - // Reconfiguring DOM elements - cardDiv.style.display = 'initial'; - welcomeDiv.innerHTML = `Welcome ${account.username}`; - signInButton.nextElementSibling.style.display = 'none'; - signInButton.setAttribute("onclick", "signOut();"); - signInButton.setAttribute('class', "btn btn-success") - signInButton.innerHTML = "Sign Out"; -} - -function updateUI(data, endpoint) { - console.log('Graph API responded at: ' + new Date().toString()); - - if (endpoint.endsWith("/me")) { - const title = document.createElement('p'); - title.innerHTML = "Title: " + data.jobTitle; - const email = document.createElement('p'); - email.innerHTML = "Mail: " + data.mail; - const phone = document.createElement('p'); - phone.innerHTML = "Phone: " + data.businessPhones[0]; - const address = document.createElement('p'); - address.innerHTML = "Location: " + data.officeLocation; - profileDiv.appendChild(title); - profileDiv.appendChild(email); - profileDiv.appendChild(phone); - profileDiv.appendChild(address); - } else if (endpoint.endsWith("/messages")) { - if (data.value.length < 1) { - alert("Your mailbox is empty!") - } else { - const tabList = document.getElementById("list-tab"); - const tabContent = document.getElementById("nav-tabContent"); - - data.value.map((d, i) => { - // Keeping it simple - if (i < 10) { - const listItem = document.createElement("a"); - listItem.setAttribute("class", "list-group-item list-group-item-action") - listItem.setAttribute("id", "list" + i + "list") - listItem.setAttribute("data-toggle", "list") - listItem.setAttribute("href", "#list" + i) - listItem.setAttribute("role", "tab") - listItem.setAttribute("aria-controls", i) - listItem.innerHTML = d.subject; - tabList.appendChild(listItem) - - const contentItem = document.createElement("div"); - contentItem.setAttribute("class", "tab-pane fade") - contentItem.setAttribute("id", "list" + i) - contentItem.setAttribute("role", "tabpanel") - contentItem.setAttribute("aria-labelledby", "list" + i + "list") - contentItem.innerHTML = " from: " + d.from.emailAddress.address + "

" + d.bodyPreview + "..."; - tabContent.appendChild(contentItem); - } - }); - } - } -} diff --git a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/navigateToLoginPage/auth.js b/samples/msal-browser-samples/VanillaJSTestApp2.0/app/navigateToLoginPage/auth.js deleted file mode 100644 index d52535e3f0..0000000000 --- a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/navigateToLoginPage/auth.js +++ /dev/null @@ -1,90 +0,0 @@ -// Browser check variables -// If you support IE, our recommendation is that you sign-in using Redirect APIs -// If you as a developer are testing using Edge InPrivate mode, please add "isEdge" to the if check -const ua = window.navigator.userAgent; -const msie = ua.indexOf("MSIE "); -const msie11 = ua.indexOf("Trident/"); -const msedge = ua.indexOf("Edge/"); -const isIE = msie > 0 || msie11 > 0; -const isEdge = msedge > 0; - -let signInType; -let accountId = ""; - -// Create the main myMSALObj instance -// configuration parameters are located at authConfig.js -const myMSALObj = new msal.PublicClientApplication(msalConfig); - -// Redirect: once login is successful and redirects with tokens, call Graph API -myMSALObj.initialize().then(() => { - myMSALObj.handleRedirectPromise().then(handleResponse).catch(err => { - console.error(err); - }); -}); - -function handleResponse(resp) { - if (resp !== null) { - accountId = resp.account.homeAccountId; - showWelcomeMessage(resp.account); - } else { - // need to call getAccount here? - const currentAccounts = myMSALObj.getAllAccounts(); - if (!currentAccounts || currentAccounts.length < 1) { - return; - } else if (currentAccounts.length > 1) { - // Add choose account code here - } else if (currentAccounts.length === 1) { - accountId = currentAccounts[0].homeAccountId; - showWelcomeMessage(currentAccounts[0]); - } - } -} - -async function signIn(method) { - signInType = isIE ? "loginRedirect" : method; - if (signInType === "loginPopup") { - return myMSALObj.loginPopup(loginRequest).then(handleResponse).catch(function (error) { - console.log(error); - }); - } else if (signInType === "loginRedirect") { - return myMSALObj.loginRedirect(loginRequest) - } -} - -function signOut() { - const logoutRequest = { - account: myMSALObj.getAccount({accountId}) - }; - - myMSALObj.logoutRedirect(logoutRequest); -} - -async function getTokenPopup(request, account) { - request.account = account; - return await myMSALObj.acquireTokenSilent(request).catch(async (error) => { - console.log("silent token acquisition fails."); - if (error instanceof msal.InteractionRequiredAuthError) { - console.log("acquiring token using popup"); - return myMSALObj.acquireTokenPopup(request).catch(error => { - console.error(error); - }); - } else { - console.error(error); - } - }); -} - -// This function can be removed if you do not need to support IE -async function getTokenRedirect(request, account) { - request.account = account; - return await myMSALObj.acquireTokenSilent(request).catch(async (error) => { - console.log("silent token acquisition fails."); - if (error instanceof msal.InteractionRequiredAuthError) { - // fallback to interaction when silent call fails - console.log("acquiring token using redirect"); - myMSALObj.acquireTokenRedirect(request); - } else { - console.error(error); - } - }); -} diff --git a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/navigateToLoginPage/authConfig.js b/samples/msal-browser-samples/VanillaJSTestApp2.0/app/navigateToLoginPage/authConfig.js deleted file mode 100644 index 08c6c4055e..0000000000 --- a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/navigateToLoginPage/authConfig.js +++ /dev/null @@ -1,58 +0,0 @@ -// Config object to be passed to Msal on creation -const msalConfig = { - auth: { - clientId: "b5c2e510-4a17-4feb-b219-e55aa5b74144", - authority: "https://login.microsoftonline.com/common", - navigateToLoginRequestUrl: false, - redirectUri: "http://localhost:30662/" - }, - 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 - }, - system: { - allowPlatformBroker: false, // Disables WAM Broker - loggerOptions: { - loggerCallback: (level, message, containsPii) => { - if (containsPii) { - return; - } - switch (level) { - case msal.LogLevel.Error: - console.error(message); - return; - case msal.LogLevel.Info: - console.info(message); - return; - case msal.LogLevel.Verbose: - console.debug(message); - return; - case msal.LogLevel.Warning: - console.warn(message); - return; - } - } - } - } -}; - -// Add here scopes for id token to be used at MS Identity Platform endpoints. -const loginRequest = { - scopes: ["User.Read"] -}; - -// Add here the endpoints for MS Graph API services you would like to use. -const graphConfig = { - graphMeEndpoint: "https://graph.microsoft.com/v1.0/me", - graphMailEndpoint: "https://graph.microsoft.com/v1.0/me/messages" -}; - -// Add here scopes for access token to be used at MS Graph API endpoints. -const tokenRequest = { - scopes: ["Mail.Read"], - forceRefresh: false // Set this to "true" to skip a cached token and go to the server to get a new token -}; - -const silentRequest = { - scopes: ["openid", "profile", "User.Read", "Mail.Read"] -}; diff --git a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/navigateToLoginPage/graph.js b/samples/msal-browser-samples/VanillaJSTestApp2.0/app/navigateToLoginPage/graph.js deleted file mode 100644 index 92b6722e01..0000000000 --- a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/navigateToLoginPage/graph.js +++ /dev/null @@ -1,64 +0,0 @@ -// Helper function to call MS Graph API endpoint -// using authorization bearer token scheme -function callMSGraph(endpoint, accessToken, callback) { - const headers = new Headers(); - const bearer = `Bearer ${accessToken}`; - - headers.append("Authorization", bearer); - - const options = { - method: "GET", - headers: headers - }; - - console.log('request made to Graph API at: ' + new Date().toString()); - - fetch(endpoint, options) - .then(response => response.json()) - .then(response => callback(response, endpoint)) - .catch(error => console.log(error)); -} - -async function seeProfile() { - const currentAcc = myMSALObj.getAccount({accountId}); - if (currentAcc) { - const response = await getTokenPopup(loginRequest, currentAcc).catch(error => { - console.log(error); - }); - callMSGraph(graphConfig.graphMeEndpoint, response.accessToken, updateUI); - profileButton.style.display = 'none'; - } -} - -async function readMail() { - const currentAcc = myMSALObj.getAccount({accountId}); - if (currentAcc) { - const response = await getTokenPopup(tokenRequest, currentAcc).catch(error => { - console.log(error); - }); - callMSGraph(graphConfig.graphMailEndpoint, response.accessToken, updateUI); - mailButton.style.display = 'none'; - } -} - -async function seeProfileRedirect() { - const currentAcc = myMSALObj.getAccount({accountId}); - if (currentAcc) { - const response = await getTokenRedirect(loginRequest, currentAcc).catch(error => { - console.log(error); - }); - callMSGraph(graphConfig.graphMeEndpoint, response.accessToken, updateUI); - profileButton.style.display = 'none'; - } -} - -async function readMailRedirect() { - const currentAcc = myMSALObj.getAccount({accountId}); - if (currentAcc) { - const response = await getTokenRedirect(tokenRequest, currentAcc).catch(error => { - console.log(error); - }); - callMSGraph(graphConfig.graphMailEndpoint, response.accessToken, updateUI); - mailButton.style.display = 'none'; - } -} diff --git a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/navigateToLoginPage/index.html b/samples/msal-browser-samples/VanillaJSTestApp2.0/app/navigateToLoginPage/index.html deleted file mode 100644 index d79b90dafb..0000000000 --- a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/navigateToLoginPage/index.html +++ /dev/null @@ -1,81 +0,0 @@ - - - - - - - Quickstart | MSAL.JS Vanilla JavaScript SPA - - - - - - - - - - -
-
Vanilla JavaScript SPA calling MS Graph API with MSAL.JS
-
-
- -
-
-
-
-
-
-
- -
-
-
-
- - - - - - - - - - - - - - \ No newline at end of file diff --git a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/navigateToLoginPage/ui.js b/samples/msal-browser-samples/VanillaJSTestApp2.0/app/navigateToLoginPage/ui.js deleted file mode 100644 index a4e139b2dc..0000000000 --- a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/navigateToLoginPage/ui.js +++ /dev/null @@ -1,66 +0,0 @@ -// Select DOM elements to work with -const welcomeDiv = document.getElementById("WelcomeMessage"); -const signInButton = document.getElementById("SignIn"); -const cardDiv = document.getElementById("card-div"); -const mailButton = document.getElementById("readMail"); -const profileButton = document.getElementById("seeProfile"); -const profileDiv = document.getElementById("profile-div"); - -function showWelcomeMessage(account) { - // Reconfiguring DOM elements - cardDiv.style.display = 'initial'; - welcomeDiv.innerHTML = `Welcome ${account.username}`; - signInButton.nextElementSibling.style.display = 'none'; - signInButton.setAttribute("onclick", "signOut();"); - signInButton.setAttribute('class', "btn btn-success") - signInButton.innerHTML = "Sign Out"; -} - -function updateUI(data, endpoint) { - console.log('Graph API responded at: ' + new Date().toString()); - - if (endpoint === graphConfig.graphMeEndpoint) { - const title = document.createElement('p'); - title.innerHTML = "Title: " + data.jobTitle; - const email = document.createElement('p'); - email.innerHTML = "Mail: " + data.mail; - const phone = document.createElement('p'); - phone.innerHTML = "Phone: " + data.businessPhones[0]; - const address = document.createElement('p'); - address.innerHTML = "Location: " + data.officeLocation; - profileDiv.appendChild(title); - profileDiv.appendChild(email); - profileDiv.appendChild(phone); - profileDiv.appendChild(address); - } else if (endpoint === graphConfig.graphMailEndpoint) { - if (data.value.length < 1) { - alert("Your mailbox is empty!") - } else { - const tabList = document.getElementById("list-tab"); - const tabContent = document.getElementById("nav-tabContent"); - - data.value.map((d, i) => { - // Keeping it simple - if (i < 10) { - const listItem = document.createElement("a"); - listItem.setAttribute("class", "list-group-item list-group-item-action") - listItem.setAttribute("id", "list" + i + "list") - listItem.setAttribute("data-toggle", "list") - listItem.setAttribute("href", "#list" + i) - listItem.setAttribute("role", "tab") - listItem.setAttribute("aria-controls", i) - listItem.innerHTML = d.subject; - tabList.appendChild(listItem) - - const contentItem = document.createElement("div"); - contentItem.setAttribute("class", "tab-pane fade") - contentItem.setAttribute("id", "list" + i) - contentItem.setAttribute("role", "tabpanel") - contentItem.setAttribute("aria-labelledby", "list" + i + "list") - contentItem.innerHTML = " from: " + d.from.emailAddress.address + "

" + d.bodyPreview + "..."; - tabContent.appendChild(contentItem); - } - }); - } - } -} diff --git a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/sample_template/index.html b/samples/msal-browser-samples/VanillaJSTestApp2.0/app/sample_template/index.html deleted file mode 100644 index 79ab3d9628..0000000000 --- a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/sample_template/index.html +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - Quickstart | MSAL.JS Vanilla JavaScript SPA - - - - - - - - - -
-
Vanilla JavaScript SPA calling MS Graph API with MSAL.JS
-
-
- -
-
-
-
-
-
-
- -
-
-
-
- - - - - - - - - diff --git a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/sample_template/test/template.spec.ts b/samples/msal-browser-samples/VanillaJSTestApp2.0/app/sample_template/test/template.spec.ts deleted file mode 100644 index c880ea7706..0000000000 --- a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/sample_template/test/template.spec.ts +++ /dev/null @@ -1,61 +0,0 @@ -import * as puppeteer from "puppeteer"; -import fs from "fs"; - -const SCREENSHOT_BASE_FOLDER_NAME = `${__dirname}/screenshots`; -let SCREENSHOT_NUM = 0; - -function setupScreenshotDir() { - if (!fs.existsSync(`${SCREENSHOT_BASE_FOLDER_NAME}`)) { - fs.mkdirSync(SCREENSHOT_BASE_FOLDER_NAME); - } -} - -async function takeScreenshot(page: puppeteer.Page, testName: string, screenshotName: string): Promise { - const screenshotFolderName = `${SCREENSHOT_BASE_FOLDER_NAME}/${testName}` - if (!fs.existsSync(`${screenshotFolderName}`)) { - fs.mkdirSync(screenshotFolderName); - } - await page.screenshot({ path: `${screenshotFolderName}/${++SCREENSHOT_NUM}_${screenshotName}.png` }); -} - -async function enterCredentials(page: puppeteer.Page, testName: string): Promise { - await page.waitForNavigation({ waitUntil: "networkidle0"}); - await takeScreenshot(page, testName, `loginPage`); - await page.type("#i0116", "IDLAB@msidlab0.ccsctp.net"); - await page.click("#idSIButton9"); - await page.waitForNavigation({ waitUntil: "networkidle0"}); - await takeScreenshot(page, testName, `pwdInputPage`); - await page.type("#i0118", ""); - await page.click("#idSIButton9"); -} - -describe("Browser tests", function () { - let browser: puppeteer.Browser; - beforeAll(async () => { - setupScreenshotDir(); - browser = await puppeteer.launch({ - headless: true, - ignoreDefaultArgs: ['--no-sandbox', '–disable-setuid-sandbox'] - }); - }); - - let context: puppeteer.BrowserContext; - let page: puppeteer.Page; - beforeEach(async () => { - SCREENSHOT_NUM = 0; - context = await browser.createBrowserContext(); - page = await context.newPage(); - await page.goto('http://localhost:30662/'); - }); - - afterEach(async () => { - await page.close(); - }); - - afterAll(async () => { - await context.close(); - await browser.close(); - }); - - // TODO: Add browser tests for sample here -}); diff --git a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssh/auth.js b/samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssh/auth.js deleted file mode 100644 index 74adf1888e..0000000000 --- a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssh/auth.js +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Browser check variables - * If you support IE, our recommendation is that you sign-in using Redirect APIs - * If you as a developer are testing using Edge InPrivate mode, please add "isEdge" to the if check - */ -const ua = window.navigator.userAgent; -const msie = ua.indexOf("MSIE "); -const msie11 = ua.indexOf("Trident/"); -const msedge = ua.indexOf("Edge/"); -const isIE = msie > 0 || msie11 > 0; -const isEdge = msedge > 0; - -let signInType; -let username = ""; -/** - * Create the main myMSALObj instance - * Configuration parameters are located at authConfig.js - */ -const myMSALObj = new msal.PublicClientApplication(msalConfig); - -// Redirect: once login is successful and redirects with tokens, call Graph API -myMSALObj.initialize().then(() => { - myMSALObj.handleRedirectPromise().then(handleResponse).catch(err => { - console.error(err); - }); -}); - -function handleResponse(resp) { - if (resp !== null) { - username = resp.account.username; - showWelcomeMessage(resp.account); - } else { - // need to call getAccount here? - const currentAccounts = myMSALObj.getAllAccounts(); - if (!currentAccounts || currentAccounts.length < 1) { - return; - } else if (currentAccounts.length > 1) { - // Add choose account code here - } else if (currentAccounts.length === 1) { - username = currentAccounts[0].username; - showWelcomeMessage(currentAccounts[0]); - } - } -} - -async function signIn(method) { - signInType = isIE ? "loginRedirect" : method; - if (signInType === "loginPopup") { - return myMSALObj.loginPopup(loginRequest).then(handleResponse).catch(function (error) { - console.log(error); - }); - } else if (signInType === "loginRedirect") { - return myMSALObj.loginRedirect(loginRequest); - } -} - -function signOut() { - const logoutRequest = { - account: myMSALObj.getAccount({username}) - }; - - myMSALObj.logoutRedirect(logoutRequest); -} - -async function fetchSshCert() { - const currentAcc = myMSALObj.getAccount({username}); - if (currentAcc) { - sshCert = getCertPopup(sshCertRequest, currentAcc).then(response => { - console.log("Response: ", response); - if (response.accessToken) { - showSshCertAcquired(); - return response.accessToken; - } - }).catch(error => { - console.log(error); - }); - } -} - -async function getCertPopup(request, account) { - request.account = account; - return await myMSALObj.acquireTokenSilent(request).catch(async (error) => { - console.log("silent token acquisition fails."); - if (error instanceof msal.InteractionRequiredAuthError) { - console.log("acquiring token using popup"); - return myMSALObj.acquireTokenPopup(request).catch(error => { - console.error(error); - }); - } else { - console.error(error); - } - }); -} - -// This function can be removed if you do not need to support IE -async function getCertRedirect(request, account) { - request.account = account; - return await myMSALObj.acquireTokenSilent(request).catch(async (error) => { - console.log("silent token acquisition fails."); - if (error instanceof msal.InteractionRequiredAuthError) { - // fallback to interaction when silent call fails - console.log("acquiring token using redirect"); - myMSALObj.acquireTokenRedirect(request); - } else { - console.error(error); - } - }); -} diff --git a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssh/authConfig.js b/samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssh/authConfig.js deleted file mode 100644 index 3fa9add64d..0000000000 --- a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssh/authConfig.js +++ /dev/null @@ -1,58 +0,0 @@ -// Config object to be passed to Msal on creation -const msalConfig = { - auth: { - clientId: "CLIENT_ID", // Replace with your Client ID - authority: "https://login.microsoftonline.com/common" - }, - 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 - }, - system: { - allowPlatformBroker: false, // Disables WAM Broker - loggerOptions: { - loggerCallback: (level, message, containsPii) => { - if (containsPii) { - return; - } - switch (level) { - case msal.LogLevel.Error: - console.error(message); - return; - case msal.LogLevel.Info: - console.info(message); - return; - case msal.LogLevel.Verbose: - console.debug(message); - return; - case msal.LogLevel.Warning: - console.warn(message); - return; - case msal.LogLevel.Trace: - console.trace(message); - return; - } - }, - logLevel: msal.LogLevel.Verbose - } - } -}; - -// Add here scopes for id token to be used at MS Identity Platform endpoints. -const loginRequest = { - scopes: ["openid", "profile"] -}; - -// SSH Public Key -const sshPublicKeyData = { - key: PUBLIC_KEY_JWK, // Replace with your SSH Public Key in JSON Web Key object format - keyId: "PUBLIC_KEY_ID" // Replace with the SSH Public Key's unique ID -}; - -// Configure SSH Certificate Request -const sshCertRequest = { - scopes: ["https://pas.windows.net/CheckMyAccess/Linux/.default"], - authenticationScheme: msal.AuthenticationScheme.SSH, - sshJwk: JSON.stringify(sshPublicKeyData.key), - sshKid: sshPublicKeyData.keyId -} diff --git a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssh/index.html b/samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssh/index.html deleted file mode 100644 index 24c1d47933..0000000000 --- a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssh/index.html +++ /dev/null @@ -1,77 +0,0 @@ - - - - - - - Ephemeral SSH Certificates | MSAL.JS Vanilla JavaScript SPA - - - - - - - - - - -
-
Vanilla JavaScript SPA calling MS Graph API with MSAL.JS
-
-
- -
-
-
-
-
-
-
- -
-
-
-
- - - - - - - - - - - - - \ No newline at end of file diff --git a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssh/ui.js b/samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssh/ui.js deleted file mode 100644 index 36ae899d21..0000000000 --- a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssh/ui.js +++ /dev/null @@ -1,25 +0,0 @@ -// Select DOM elements to work with -const welcomeDiv = document.getElementById("WelcomeMessage"); -const signInButton = document.getElementById("SignIn"); -const cardDiv = document.getElementById("card-div"); -const mailButton = document.getElementById("readMail"); -const profileButton = document.getElementById("seeProfile"); -const profileDiv = document.getElementById("profile-div"); -const popTokenAcquired = document.getElementById("SshCertAcquired"); - -function showWelcomeMessage(account) { - // Reconfiguring DOM elements - cardDiv.style.display = 'initial'; - welcomeDiv.innerHTML = `Welcome ${username}`; - signInButton.nextElementSibling.style.display = 'none'; - signInButton.setAttribute("onclick", "signOut();"); - signInButton.setAttribute('class', "btn btn-success") - signInButton.innerHTML = "Sign Out"; -} - -function showSshCertAcquired() { - const sshCertAcquired = document.createElement('p'); - sshCertAcquired.setAttribute("id", "SshCertAcquired"); - sshCertAcquired.innerHTML = "Successfully acquired SSH Certificate"; - profileDiv.appendChild(sshCertAcquired); -} diff --git a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssoSilent/auth.js b/samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssoSilent/auth.js deleted file mode 100644 index c8a15bac84..0000000000 --- a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssoSilent/auth.js +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Browser check variables - * If you support IE, our recommendation is that you sign-in using Redirect APIs - * If you as a developer are testing using Edge InPrivate mode, please add "isEdge" to the if check - */ -const ua = window.navigator.userAgent; -const msie = ua.indexOf("MSIE "); -const msie11 = ua.indexOf("Trident/"); -const msedge = ua.indexOf("Edge/"); -const isIE = msie > 0 || msie11 > 0; -const isEdge = msedge > 0; - -let signInType; -let accountId = ""; - -/* - * Create the main myMSALObj instance - * configuration parameters are located at authConfig.js - */ -const myMSALObj = new msal.PublicClientApplication(msalConfig); - -// Redirect: once login is successful and redirects with tokens, call Graph API -myMSALObj.initialize().then(() => { - myMSALObj.handleRedirectPromise().then(handleResponse).catch(err => { - console.error(err); - }); -}); - -function handleResponse(resp) { - const isInIframe = window.parent !== window; - if (!isInIframe) { - if (resp !== null) { - accountId = resp.account.homeAccountId; - showWelcomeMessage(resp.account); - getTokenRedirect(loginRequest, resp.account); - } else { - myMSALObj.ssoSilent(silentRequest).then(() => { - const currentAccounts = myMSALObj.getAllAccounts(); - accountId = currentAccounts[0].homeAccountId; - showWelcomeMessage(currentAccounts[0]); - getTokenRedirect(loginRequest, currentAccounts[0]); - }).catch(error => { - console.error("Silent Error: " + error); - if (error instanceof msal.InteractionRequiredAuthError) { - signIn("loginPopup"); - } - }); - } - } -} - -async function signIn(method) { - signInType = isIE ? "loginRedirect" : method; - if (signInType === "loginPopup") { - return myMSALObj.loginPopup(loginRequest).then(handleResponse).catch(function (error) { - console.log(error); - }); - } else if (signInType === "loginRedirect") { - return myMSALObj.loginRedirect(loginRequest); - } -} - -function signOut() { - const logoutRequest = { - account: myMSALObj.getAccount({homeAccountId}) - }; - myMSALObj.logoutRedirect(logoutRequest); -} - -async function getTokenPopup(request, account) { - request.account = account; - return await myMSALObj.acquireTokenSilent(request).catch(async (error) => { - console.log("silent token acquisition fails."); - if (error instanceof msal.InteractionRequiredAuthError) { - console.log("acquiring token using popup"); - return myMSALObj.acquireTokenPopup(request).catch(error => { - console.error(error); - }); - } else { - console.error(error); - } - }); -} - -// This function can be removed if you do not need to support IE -async function getTokenRedirect(request, account) { - request.account = account; - return await myMSALObj.acquireTokenSilent(request).catch(async (error) => { - console.log("silent token acquisition fails."); - if (error instanceof msal.InteractionRequiredAuthError) { - // fallback to interaction when silent call fails - console.log("acquiring token using redirect"); - myMSALObj.acquireTokenRedirect(request); - } else { - console.error(error); - } - }); -} diff --git a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssoSilent/authConfig.js b/samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssoSilent/authConfig.js deleted file mode 100644 index edb316d3f4..0000000000 --- a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssoSilent/authConfig.js +++ /dev/null @@ -1,56 +0,0 @@ -// Config object to be passed to Msal on creation -const msalConfig = { - auth: { - clientId: "b5c2e510-4a17-4feb-b219-e55aa5b74144", - authority: "https://login.microsoftonline.com/common" - }, - 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 - }, - system: { - allowPlatformBroker: false, // Disables WAM Broker - loggerOptions: { - loggerCallback: (level, message, containsPii) => { - if (containsPii) { - return; - } - switch (level) { - case msal.LogLevel.Error: - console.error(message); - return; - case msal.LogLevel.Info: - console.info(message); - return; - case msal.LogLevel.Verbose: - console.debug(message); - return; - case msal.LogLevel.Warning: - console.warn(message); - return; - } - } - } - } -}; - -// Add here scopes for id token to be used at MS Identity Platform endpoints. -const loginRequest = { - scopes: ["User.Read"] -}; - -// Add here the endpoints for MS Graph API services you would like to use. -const graphConfig = { - graphMeEndpoint: "https://graph.microsoft.com/v1.0/me", - graphMailEndpoint: "https://graph.microsoft.com/v1.0/me/messages" -}; - -// Add here scopes for access token to be used at MS Graph API endpoints. -const tokenRequest = { - scopes: ["Mail.Read", "openid", "profile"], - forceRefresh: false // Set this to "true" to skip a cached token and go to the server to get a new token -}; - -const silentRequest = { - loginHint: "IDLAB@msidlab0.ccsctp.net" -}; diff --git a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssoSilent/graph.js b/samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssoSilent/graph.js deleted file mode 100644 index 92b6722e01..0000000000 --- a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssoSilent/graph.js +++ /dev/null @@ -1,64 +0,0 @@ -// Helper function to call MS Graph API endpoint -// using authorization bearer token scheme -function callMSGraph(endpoint, accessToken, callback) { - const headers = new Headers(); - const bearer = `Bearer ${accessToken}`; - - headers.append("Authorization", bearer); - - const options = { - method: "GET", - headers: headers - }; - - console.log('request made to Graph API at: ' + new Date().toString()); - - fetch(endpoint, options) - .then(response => response.json()) - .then(response => callback(response, endpoint)) - .catch(error => console.log(error)); -} - -async function seeProfile() { - const currentAcc = myMSALObj.getAccount({accountId}); - if (currentAcc) { - const response = await getTokenPopup(loginRequest, currentAcc).catch(error => { - console.log(error); - }); - callMSGraph(graphConfig.graphMeEndpoint, response.accessToken, updateUI); - profileButton.style.display = 'none'; - } -} - -async function readMail() { - const currentAcc = myMSALObj.getAccount({accountId}); - if (currentAcc) { - const response = await getTokenPopup(tokenRequest, currentAcc).catch(error => { - console.log(error); - }); - callMSGraph(graphConfig.graphMailEndpoint, response.accessToken, updateUI); - mailButton.style.display = 'none'; - } -} - -async function seeProfileRedirect() { - const currentAcc = myMSALObj.getAccount({accountId}); - if (currentAcc) { - const response = await getTokenRedirect(loginRequest, currentAcc).catch(error => { - console.log(error); - }); - callMSGraph(graphConfig.graphMeEndpoint, response.accessToken, updateUI); - profileButton.style.display = 'none'; - } -} - -async function readMailRedirect() { - const currentAcc = myMSALObj.getAccount({accountId}); - if (currentAcc) { - const response = await getTokenRedirect(tokenRequest, currentAcc).catch(error => { - console.log(error); - }); - callMSGraph(graphConfig.graphMailEndpoint, response.accessToken, updateUI); - mailButton.style.display = 'none'; - } -} diff --git a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssoSilent/index.html b/samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssoSilent/index.html deleted file mode 100644 index d79b90dafb..0000000000 --- a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssoSilent/index.html +++ /dev/null @@ -1,81 +0,0 @@ - - - - - - - Quickstart | MSAL.JS Vanilla JavaScript SPA - - - - - - - - - - -
-
Vanilla JavaScript SPA calling MS Graph API with MSAL.JS
-
-
- -
-
-
-
-
-
-
- -
-
-
-
- - - - - - - - - - - - - - \ No newline at end of file diff --git a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssoSilent/ui.js b/samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssoSilent/ui.js deleted file mode 100644 index a4e139b2dc..0000000000 --- a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssoSilent/ui.js +++ /dev/null @@ -1,66 +0,0 @@ -// Select DOM elements to work with -const welcomeDiv = document.getElementById("WelcomeMessage"); -const signInButton = document.getElementById("SignIn"); -const cardDiv = document.getElementById("card-div"); -const mailButton = document.getElementById("readMail"); -const profileButton = document.getElementById("seeProfile"); -const profileDiv = document.getElementById("profile-div"); - -function showWelcomeMessage(account) { - // Reconfiguring DOM elements - cardDiv.style.display = 'initial'; - welcomeDiv.innerHTML = `Welcome ${account.username}`; - signInButton.nextElementSibling.style.display = 'none'; - signInButton.setAttribute("onclick", "signOut();"); - signInButton.setAttribute('class', "btn btn-success") - signInButton.innerHTML = "Sign Out"; -} - -function updateUI(data, endpoint) { - console.log('Graph API responded at: ' + new Date().toString()); - - if (endpoint === graphConfig.graphMeEndpoint) { - const title = document.createElement('p'); - title.innerHTML = "Title: " + data.jobTitle; - const email = document.createElement('p'); - email.innerHTML = "Mail: " + data.mail; - const phone = document.createElement('p'); - phone.innerHTML = "Phone: " + data.businessPhones[0]; - const address = document.createElement('p'); - address.innerHTML = "Location: " + data.officeLocation; - profileDiv.appendChild(title); - profileDiv.appendChild(email); - profileDiv.appendChild(phone); - profileDiv.appendChild(address); - } else if (endpoint === graphConfig.graphMailEndpoint) { - if (data.value.length < 1) { - alert("Your mailbox is empty!") - } else { - const tabList = document.getElementById("list-tab"); - const tabContent = document.getElementById("nav-tabContent"); - - data.value.map((d, i) => { - // Keeping it simple - if (i < 10) { - const listItem = document.createElement("a"); - listItem.setAttribute("class", "list-group-item list-group-item-action") - listItem.setAttribute("id", "list" + i + "list") - listItem.setAttribute("data-toggle", "list") - listItem.setAttribute("href", "#list" + i) - listItem.setAttribute("role", "tab") - listItem.setAttribute("aria-controls", i) - listItem.innerHTML = d.subject; - tabList.appendChild(listItem) - - const contentItem = document.createElement("div"); - contentItem.setAttribute("class", "tab-pane fade") - contentItem.setAttribute("id", "list" + i) - contentItem.setAttribute("role", "tabpanel") - contentItem.setAttribute("aria-labelledby", "list" + i + "list") - contentItem.innerHTML = " from: " + d.from.emailAddress.address + "

" + d.bodyPreview + "..."; - tabContent.appendChild(contentItem); - } - }); - } - } -} diff --git a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssoSilentNoHint/auth.js b/samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssoSilentNoHint/auth.js deleted file mode 100644 index 13b06af77f..0000000000 --- a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssoSilentNoHint/auth.js +++ /dev/null @@ -1,117 +0,0 @@ -// Browser check variables -// If you support IE, our recommendation is that you sign-in using Redirect APIs -// If you as a developer are testing using Edge InPrivate mode, please add "isEdge" to the if check -const ua = window.navigator.userAgent; -const msie = ua.indexOf("MSIE "); -const msie11 = ua.indexOf("Trident/"); -const msedge = ua.indexOf("Edge/"); -const isIE = msie > 0 || msie11 > 0; -const isEdge = msedge > 0; - -let signInType; -let accountId = ""; - -// Create the main myMSALObj instance -// configuration parameters are located at authConfig.js -const myMSALObj = new msal.PublicClientApplication(msalConfig); - -// Redirect: once login is successful and redirects with tokens, call Graph API -myMSALObj.initialize().then(() => { - myMSALObj.handleRedirectPromise().then(handleResponse).catch(err => { - console.error(err); - }); -}); - -function handleResponse(resp) { - if (resp !== null) { - accountId = resp.account.homeAccountId; - myMSALObj.setActiveAccount(resp.account); - showWelcomeMessage(resp.account); - } else { - // need to call getAccount here? - const currentAccounts = myMSALObj.getAllAccounts(); - if (!currentAccounts || currentAccounts.length < 1) { - myMSALObj.ssoSilent(loginRequest).then((response) => { - accountId = response.account.homeAccountId; - showWelcomeMessage(response.account); - getTokenRedirect(loginRequest, response.account); - }).catch(error => { - console.error("Silent Error: " + error); - if (error instanceof msal.InteractionRequiredAuthError) { - myMSALObj.ssoSilent(silentRequest).then((response) => { - accountId = response.account.homeAccountId; - showWelcomeMessage(response.account); - getTokenRedirect(loginRequest, response.account); - }).catch(err => { - console.error("Silent Error: " + err); - if (err instanceof msal.InteractionRequiredAuthError) { - console.log("popup sign in") - signIn("popup"); - } - }) - } - }); - return; - } else if (currentAccounts.length > 1) { - // Add choose account code here - } else if (currentAccounts.length === 1) { - const activeAccount = currentAccounts[0]; - myMSALObj.setActiveAccount(activeAccount); - accountId = activeAccount.homeAccountId; - showWelcomeMessage(activeAccount); - } - } -} - -async function signIn(method) { - signInType = isIE ? "redirect" : method; - if (signInType === "popup") { - return myMSALObj.loginPopup(loginRequest).then(handleResponse).catch(function (error) { - console.log(error); - }); - } else if (signInType === "redirect") { - return myMSALObj.loginRedirect(loginRequest) - } -} - -function signOut(interactionType) { - const logoutRequest = { - account: myMSALObj.getAccount({accountId}) - }; - - if (interactionType === "popup") { - myMSALObj.logoutPopup(logoutRequest).then(() => { - window.location.reload(); - }); - } else { - myMSALObj.logoutRedirect(logoutRequest); - } -} - -async function getTokenPopup(request, account) { - return await myMSALObj.acquireTokenSilent(request).catch(async (error) => { - console.log("silent token acquisition fails."); - if (error instanceof msal.InteractionRequiredAuthError) { - console.log("acquiring token using popup"); - return myMSALObj.acquireTokenPopup(request).catch(error => { - console.error(error); - }); - } else { - console.error(error); - } - }); -} - -// This function can be removed if you do not need to support IE -async function getTokenRedirect(request, account) { - return await myMSALObj.acquireTokenSilent(request).catch(async (error) => { - console.log("silent token acquisition fails."); - if (error instanceof msal.InteractionRequiredAuthError) { - // fallback to interaction when silent call fails - console.log("acquiring token using redirect"); - myMSALObj.acquireTokenRedirect(request); - } else { - console.error(error); - } - }); -} diff --git a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssoSilentNoHint/authConfig.js b/samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssoSilentNoHint/authConfig.js deleted file mode 100644 index 8fbf4a41e9..0000000000 --- a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssoSilentNoHint/authConfig.js +++ /dev/null @@ -1,58 +0,0 @@ -// Config object to be passed to Msal on creation -const msalConfig = { - auth: { - clientId: "b5c2e510-4a17-4feb-b219-e55aa5b74144", - authority: "https://login.microsoftonline.com/common" - }, - 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 - }, - system: { - allowPlatformBroker: false, // Disables WAM Broker - loggerOptions: { - loggerCallback: (level, message, containsPii) => { - if (containsPii) { - return; - } - switch (level) { - case msal.LogLevel.Error: - console.error(message); - return; - case msal.LogLevel.Info: - console.info(message); - return; - case msal.LogLevel.Verbose: - console.debug(message); - return; - case msal.LogLevel.Warning: - console.warn(message); - return; - } - } - } - } -}; - -// Add here scopes for id token to be used at MS Identity Platform endpoints. -const loginRequest = { - scopes: ["User.Read"] -}; - -// Add here the endpoints for MS Graph API services you would like to use. -const graphConfig = { - graphMeEndpoint: "https://graph.microsoft.com/v1.0/me", - graphMailEndpoint: "https://graph.microsoft.com/v1.0/me/messages" -}; - -// Add here scopes for access token to be used at MS Graph API endpoints. -const tokenRequest = { - scopes: ["Mail.Read"], - forceRefresh: false // Set this to "true" to skip a cached token and go to the server to get a new token -}; - -const silentRequest = { - loginHint: "IDLAB@msidlab0.ccsctp.net" -}; - -const logoutRequest = {} diff --git a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssoSilentNoHint/graph.js b/samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssoSilentNoHint/graph.js deleted file mode 100644 index 92b6722e01..0000000000 --- a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssoSilentNoHint/graph.js +++ /dev/null @@ -1,64 +0,0 @@ -// Helper function to call MS Graph API endpoint -// using authorization bearer token scheme -function callMSGraph(endpoint, accessToken, callback) { - const headers = new Headers(); - const bearer = `Bearer ${accessToken}`; - - headers.append("Authorization", bearer); - - const options = { - method: "GET", - headers: headers - }; - - console.log('request made to Graph API at: ' + new Date().toString()); - - fetch(endpoint, options) - .then(response => response.json()) - .then(response => callback(response, endpoint)) - .catch(error => console.log(error)); -} - -async function seeProfile() { - const currentAcc = myMSALObj.getAccount({accountId}); - if (currentAcc) { - const response = await getTokenPopup(loginRequest, currentAcc).catch(error => { - console.log(error); - }); - callMSGraph(graphConfig.graphMeEndpoint, response.accessToken, updateUI); - profileButton.style.display = 'none'; - } -} - -async function readMail() { - const currentAcc = myMSALObj.getAccount({accountId}); - if (currentAcc) { - const response = await getTokenPopup(tokenRequest, currentAcc).catch(error => { - console.log(error); - }); - callMSGraph(graphConfig.graphMailEndpoint, response.accessToken, updateUI); - mailButton.style.display = 'none'; - } -} - -async function seeProfileRedirect() { - const currentAcc = myMSALObj.getAccount({accountId}); - if (currentAcc) { - const response = await getTokenRedirect(loginRequest, currentAcc).catch(error => { - console.log(error); - }); - callMSGraph(graphConfig.graphMeEndpoint, response.accessToken, updateUI); - profileButton.style.display = 'none'; - } -} - -async function readMailRedirect() { - const currentAcc = myMSALObj.getAccount({accountId}); - if (currentAcc) { - const response = await getTokenRedirect(tokenRequest, currentAcc).catch(error => { - console.log(error); - }); - callMSGraph(graphConfig.graphMailEndpoint, response.accessToken, updateUI); - mailButton.style.display = 'none'; - } -} diff --git a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssoSilentNoHint/index.html b/samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssoSilentNoHint/index.html deleted file mode 100644 index 79aae7e9f4..0000000000 --- a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssoSilentNoHint/index.html +++ /dev/null @@ -1,81 +0,0 @@ - - - - - - - Quickstart | MSAL.JS Vanilla JavaScript SPA - - - - - - - - - - -
-
Vanilla JavaScript SPA calling MS Graph API with MSAL.JS
-
-
- -
-
-
-
-
-
-
- -
-
-
-
- - - - - - - - - - - - - - \ No newline at end of file diff --git a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssoSilentNoHint/ui.js b/samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssoSilentNoHint/ui.js deleted file mode 100644 index e248605008..0000000000 --- a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/ssoSilentNoHint/ui.js +++ /dev/null @@ -1,70 +0,0 @@ -// Select DOM elements to work with -const welcomeDiv = document.getElementById("WelcomeMessage"); -const signInButton = document.getElementById("SignIn"); -const popupButton = document.getElementById("popup"); -const redirectButton = document.getElementById("redirect"); -const cardDiv = document.getElementById("card-div"); -const mailButton = document.getElementById("readMail"); -const profileButton = document.getElementById("seeProfile"); -const profileDiv = document.getElementById("profile-div"); - -function showWelcomeMessage(account) { - // Reconfiguring DOM elements - cardDiv.style.display = 'initial'; - welcomeDiv.innerHTML = `Welcome ${account.username}`; - signInButton.setAttribute('class', "btn btn-success dropdown-toggle"); - signInButton.innerHTML = "Sign Out"; - popupButton.setAttribute('onClick', "signOut(this.id)"); - popupButton.innerHTML = "Sign Out with Popup"; - redirectButton.setAttribute('onClick', "signOut(this.id)"); - redirectButton.innerHTML = "Sign Out with Redirect"; -} - -function updateUI(data, endpoint) { - console.log('Graph API responded at: ' + new Date().toString()); - - if (endpoint === graphConfig.graphMeEndpoint) { - const title = document.createElement('p'); - title.innerHTML = "Title: " + data.jobTitle; - const email = document.createElement('p'); - email.innerHTML = "Mail: " + data.mail; - const phone = document.createElement('p'); - phone.innerHTML = "Phone: " + data.businessPhones[0]; - const address = document.createElement('p'); - address.innerHTML = "Location: " + data.officeLocation; - profileDiv.appendChild(title); - profileDiv.appendChild(email); - profileDiv.appendChild(phone); - profileDiv.appendChild(address); - } else if (endpoint === graphConfig.graphMailEndpoint) { - if (data.value.length < 1) { - alert("Your mailbox is empty!") - } else { - const tabList = document.getElementById("list-tab"); - const tabContent = document.getElementById("nav-tabContent"); - - data.value.map((d, i) => { - // Keeping it simple - if (i < 10) { - const listItem = document.createElement("a"); - listItem.setAttribute("class", "list-group-item list-group-item-action") - listItem.setAttribute("id", "list" + i + "list") - listItem.setAttribute("data-toggle", "list") - listItem.setAttribute("href", "#list" + i) - listItem.setAttribute("role", "tab") - listItem.setAttribute("aria-controls", i) - listItem.innerHTML = d.subject; - tabList.appendChild(listItem) - - const contentItem = document.createElement("div"); - contentItem.setAttribute("class", "tab-pane fade") - contentItem.setAttribute("id", "list" + i) - contentItem.setAttribute("role", "tabpanel") - contentItem.setAttribute("aria-labelledby", "list" + i + "list") - contentItem.innerHTML = " from: " + d.from.emailAddress.address + "

" + d.bodyPreview + "..."; - tabContent.appendChild(contentItem); - } - }); - } - } -} diff --git a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/wamBroker/README.md b/samples/msal-browser-samples/VanillaJSTestApp2.0/app/wamBroker/README.md deleted file mode 100644 index dbaa6b1e21..0000000000 --- a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/wamBroker/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# WAM Broker Sample - -This sample can be used to acquire device bound tokens from WAM (Web Account Manager). This feature is currently only available on Windows machines using the [Windows Accounts Chrome extension](https://chrome.google.com/webstore/detail/windows-accounts/ppnbnpeolgkicgegkbkbjmhlideopiji). - -This sample must be served over https by running the following command: - -```bash -npm run generate:certs -npm start -- --s 'wamBroker' --https -``` diff --git a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/wamBroker/auth.js b/samples/msal-browser-samples/VanillaJSTestApp2.0/app/wamBroker/auth.js deleted file mode 100644 index 9a46cf343c..0000000000 --- a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/wamBroker/auth.js +++ /dev/null @@ -1,78 +0,0 @@ -let signInType; -let accountId = ""; - -// Create the main myMSALObj instance -// configuration parameters are located at authConfig.js -const myMSALObj = new msal.PublicClientApplication(msalConfig); -myMSALObj.initialize().then(() => { - // Redirect: once login is successful and redirects with tokens, call Graph API - myMSALObj.handleRedirectPromise().then(handleResponse).catch(err => { - console.error(err); - }); -}); - - -function handleResponse(resp) { - if (resp !== null) { - accountId = resp.account.homeAccountId; - myMSALObj.setActiveAccount(resp.account); - showWelcomeMessage(resp.account); - } else { - // need to call getAccount here? - const currentAccounts = myMSALObj.getAllAccounts(); - if (!currentAccounts || currentAccounts.length < 1) { - return; - } else if (currentAccounts.length > 1) { - // Add choose account code here - } else if (currentAccounts.length === 1) { - const activeAccount = currentAccounts[0]; - myMSALObj.setActiveAccount(activeAccount); - accountId = activeAccount.homeAccountId; - showWelcomeMessage(activeAccount); - } - } -} - -async function signIn(signInType) { - if (signInType === "popup") { - return myMSALObj.loginPopup(loginRequest).then(handleResponse).catch(function (error) { - console.log({...error}); - console.log(error); - }); - } else if (signInType === "redirect") { - return myMSALObj.loginRedirect(loginRequest) - } -} - -function signOut(interactionType) { - const logoutRequest = { - account: myMSALObj.getAccount({accountId}) - }; - - if (interactionType === "popup") { - myMSALObj.logoutPopup(logoutRequest).then(() => { - window.location.reload(); - }); - } else { - myMSALObj.logoutRedirect(logoutRequest); - } -} - -async function getTokenPopup(request, account) { - const startTime = Date.now(); - return await myMSALObj.acquireTokenSilent(request).then((response) => { - console.log(`Token acquisition time elapsed: ${Date.now() - startTime}ms`); - console.log(response); - return response; - }).catch(async (error) => { - console.log("silent token acquisition fails."); - if (error instanceof msal.InteractionRequiredAuthError) { - console.log("acquiring token using popup"); - return myMSALObj.acquireTokenPopup(request).catch(error => { - console.error(error); - }); - } else { - console.error(error); - } - }); -} diff --git a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/wamBroker/authConfig.js b/samples/msal-browser-samples/VanillaJSTestApp2.0/app/wamBroker/authConfig.js deleted file mode 100644 index 602c16b197..0000000000 --- a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/wamBroker/authConfig.js +++ /dev/null @@ -1,70 +0,0 @@ -// demo usage of isPlatformBrokerAvailable API -const isPlatformBrokerAvailable = msal.isPlatformBrokerAvailable().then((isAvailable) => { - console.log(`isNativeAvailable: ${isAvailable}`); - return isAvailable; -}).catch((error) => { - console.error("Error checking if platform broker is available:", error); -}); - -// Config object to be passed to Msal on creation -const msalConfig = { - auth: { - clientId: "591ddbcc-105b-42c5-89e6-c7638c4124d4", - authority: "https://login.microsoftonline.com/f645ad92-e38d-4d1a-b510-d1b09a74a8ca" - }, - 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 - }, - system: { - loggerOptions: { - loggerCallback: (level, message, containsPii) => { - if (containsPii) { - return; - } - switch (level) { - case msal.LogLevel.Error: - console.error(message); - return; - case msal.LogLevel.Info: - console.info(message); - return; - case msal.LogLevel.Verbose: - console.debug(message); - return; - case msal.LogLevel.Warning: - console.warn(message); - return; - case msal.LogLevel.Trace: - console.log(message); - return; - } - }, - logLevel: msal.LogLevel.Trace - }, - allowPlatformBroker: true // For demonstration purposes, allowPlatformBroker is true by default as of MSAL Browser v3 - } -}; - -// Add here scopes for id token to be used at MS Identity Platform endpoints. -const loginRequest = { - scopes: ["User.Read"] -}; - -// Add here the endpoints for MS Graph API services you would like to use. -const graphConfig = { - graphMeEndpoint: "https://graph.microsoft.com/v1.0/me", - graphMailEndpoint: "https://graph.microsoft.com/v1.0/me/messages" -}; - -// Add here scopes for access token to be used at MS Graph API endpoints. -const tokenRequest = { - scopes: ["Mail.Read"], - forceRefresh: false // Set this to "true" to skip a cached token and go to the server to get a new token -}; - -const silentRequest = { - scopes: ["openid", "profile", "User.Read", "Mail.Read"] -}; - -const logoutRequest = {} diff --git a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/wamBroker/graph.js b/samples/msal-browser-samples/VanillaJSTestApp2.0/app/wamBroker/graph.js deleted file mode 100644 index da47fb869a..0000000000 --- a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/wamBroker/graph.js +++ /dev/null @@ -1,30 +0,0 @@ -// Helper function to call MS Graph API endpoint -// using authorization bearer token scheme -function callMSGraph(endpoint, accessToken, callback) { - const headers = new Headers(); - const bearer = `Bearer ${accessToken}`; - - headers.append("Authorization", bearer); - - const options = { - method: "GET", - headers: headers - }; - - console.log('request made to Graph API at: ' + new Date().toString()); - - fetch(endpoint, options) - .then(response => response.json()) - .then(response => callback(response, endpoint)) - .catch(error => console.log(error)); -} - -async function seeProfile() { - const currentAcc = myMSALObj.getAccount({accountId}); - if (currentAcc) { - const response = await getTokenPopup(loginRequest, currentAcc).catch(error => { - console.log(error); - }); - callMSGraph(graphConfig.graphMeEndpoint, response.accessToken, updateUI); - } -} diff --git a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/wamBroker/index.html b/samples/msal-browser-samples/VanillaJSTestApp2.0/app/wamBroker/index.html deleted file mode 100644 index 99526f1bfa..0000000000 --- a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/wamBroker/index.html +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - - Quickstart | MSAL.JS Vanilla JavaScript SPA - - - - - - - - - - -
-
Vanilla JavaScript SPA calling MS Graph API with MSAL.JS
-
-
- -
-
-
-
-
-
-
- -
-
-
-
- - - - - - - - - - - - - - \ No newline at end of file diff --git a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/wamBroker/ui.js b/samples/msal-browser-samples/VanillaJSTestApp2.0/app/wamBroker/ui.js deleted file mode 100644 index f01d468ec1..0000000000 --- a/samples/msal-browser-samples/VanillaJSTestApp2.0/app/wamBroker/ui.js +++ /dev/null @@ -1,41 +0,0 @@ -// Select DOM elements to work with -const welcomeDiv = document.getElementById("WelcomeMessage"); -const signInButton = document.getElementById("SignIn"); -const popupButton = document.getElementById("popup"); -const redirectButton = document.getElementById("redirect"); -const cardDiv = document.getElementById("card-div"); -const mailButton = document.getElementById("readMail"); -const profileButton = document.getElementById("seeProfile"); -const profileDiv = document.getElementById("profile-div"); - -function showWelcomeMessage(account) { - // Reconfiguring DOM elements - cardDiv.style.display = 'initial'; - welcomeDiv.innerHTML = `Welcome ${account.username}`; - signInButton.setAttribute('class', "btn btn-success dropdown-toggle"); - signInButton.innerHTML = "Sign Out"; - popupButton.setAttribute('onClick', "signOut(this.id)"); - popupButton.innerHTML = "Sign Out with Popup"; - redirectButton.setAttribute('onClick', "signOut(this.id)"); - redirectButton.innerHTML = "Sign Out with Redirect"; -} - -function updateUI(data, endpoint) { - console.log('Graph API responded at: ' + new Date().toString()); - - if (endpoint === graphConfig.graphMeEndpoint) { - const title = document.createElement('p'); - title.innerHTML = "Title: " + data.jobTitle; - const email = document.createElement('p'); - email.innerHTML = "Mail: " + data.mail; - const phone = document.createElement('p'); - phone.innerHTML = "Phone: " + data.businessPhones[0]; - const address = document.createElement('p'); - address.innerHTML = "Location: " + data.officeLocation; - profileDiv.innerHTML = ""; - profileDiv.appendChild(title); - profileDiv.appendChild(email); - profileDiv.appendChild(phone); - profileDiv.appendChild(address); - } -} diff --git a/samples/msal-browser-samples/vue3-sample-app/.npmrc b/samples/msal-browser-samples/vue3-sample-app/.npmrc deleted file mode 100644 index 9cf9495031..0000000000 --- a/samples/msal-browser-samples/vue3-sample-app/.npmrc +++ /dev/null @@ -1 +0,0 @@ -package-lock=false \ No newline at end of file diff --git a/samples/msal-browser-samples/vue3-sample-app/README.md b/samples/msal-browser-samples/vue3-sample-app/README.md deleted file mode 100644 index 6625a9e63e..0000000000 --- a/samples/msal-browser-samples/vue3-sample-app/README.md +++ /dev/null @@ -1,218 +0,0 @@ -# MSAL.js + Vue 3 + TypeScript Sample - -## About this sample - -This sample demonstrates one way you can integrate the `@azure/msal-browser` package into your Vue 3 application using the [composition API](https://v3.vuejs.org/api/composition-api.html). It is not exhaustive and there may be simpler or more complex solutions depending on your specific use case. - -⚠️ This sample is currently for demonstration purposes only. Support will be limited. - -## How to run the sample - -### Pre-requisites - -- Ensure [all pre-requisites](../../../lib/msal-browser/README.md#prerequisites) have been completed to run `@azure/msal-browser`. -- Install node.js if needed (). - -### Configure the application - -- Open `./src/authConfig.js` in an editor. -- Replace client id with the Application (client) ID from the portal registration, or use the currently configured lab registration. - - Optionally, you may replace any of the other parameters, or you can remove them and use the default values. - -### Install npm dependencies for sample - -```bash -npm install -``` - -### Running the sample - -```bash -npm start -``` - -1. Open [http://localhost:3000](http://localhost:3000) to view it in the browser. - -The page will reload if you make edits. -You will also see any lint errors in the console. - -- In the web page, hover over the "Sign In" button and select either `Sign in using Popup` or `Sign in using Redirect` to begin the auth flow. -- Navigate directly to one of the example pages (/profile or /profilenoguard) to invoke a login on page load and see your profile information using the Microsoft Graph API - -## How this sample works - -This sample demonstrates how you can integrate `@azure/msal-browser` into your Vue application. It is best if you familiarize yourself with the `@azure/msal-browser` package first, as this sample will build on many of the concepts defined there. You'll find the `msal-browser` package [here](https://github.com/AzureAD/microsoft-authentication-library-for-js/tree/dev/lib/msal-browser) and you'll find a variety of docs you may find useful [here](https://github.com/AzureAD/microsoft-authentication-library-for-js/tree/dev/lib/msal-browser/docs). The following sections will walk you through each part of this sample and explain a little bit about how it works. - -### Configuration - -You'll find the MSAL configuration and `PublicClientApplication` instantiation in `authConfig.ts`. It's very important that `PublicClientApplication` is initialized only once per pageload and as such should not be initialized inside any Vue components, but rather outside the context of Vue and passed in. - -- The `clientId` is the most important, and only required parameter, as it maps to your app registration in the Microsoft Entra admin center. -- The `authority` represents the Microsoft Entra ID instance and tenant that MSAL.js will use the sign users in. This parameter controls the audience of your app. - > :information_source: If you need to sign users in with Azure Active Directory B2C, this parameter should be set to the [B2C tenanted authority](../../../lib/msal-common/docs/authority.md#azure-ad-b2c) with the default user-flow/custom policy that will be used for sign-ins and token acquisitions. To learn more about how to handle B2C user-flows and/or custom policies with MSAL.js, please refer to [react-b2c-sample](../../msal-react-samples/b2c-sample/) and/or [angular-b2c-sample](../../msal-angular-v2-samples/angular-b2c-sample-app/). -- The `redirectUri` and `postLogoutRedirectUri` represent where Microsoft Entra ID will redirect you back to after logging in and must be registered on your app registration as type "SPA". If you do not provide these, MSAL.js will use the current page by default. - -The `cacheLocation` configures where you want your tokens to be stored. SessionStorage is the default, if this option is not provided. - -```javascript -const msalConfig = { - auth: { - clientId: "ENTER_YOUR_CLIENT_ID_HERE", - authority: - "https://login.microsoftonline.com/ENTER_YOUR_TENANT_ID_HERE", - redirectUri: "/", // Must be registered as a SPA redirectURI on your app registration - postLogoutRedirectUri: "/", // Must be registered as a SPA redirectURI on your app registrationregistration - }, - cache: { - cacheLocation: "localStorage", // Options are localStorage, sessionStorage, memoryStorage - }, -}; - -export const msalInstance = new PublicClientApplication(msalConfig); -``` - -You can read more about configuring MSAL.js and the complete set of options [here](https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/configuration.md) - -### MsalPlugin - -MSAL.js integration with Vue all starts with the `msalPlugin` defined in `src/plugins/msalPlugin.ts`. When installed in your Vue app this plugin registers an event listener that manages some global state, such as any interaction currently in progress and the accounts signed in. - -In `main.ts` you'll find the instantiation of the Vue app and installation of plugins. The most important part, with regards to MSAL.js, is to instruct Vue to "use" the `msalPlugin`. - -```javascript -import { createApp } from "vue"; -import App from "./App.vue"; // Your root component -import { msalPlugin } from "./plugins/msalPlugin"; -import { msalInstance } from "./authConfig"; - -const app = createApp(App); -app.use(msalPlugin, msalInstance); -app.mount("#app"); -``` - -### Composition APIs - -This sample demonstrates how you can write a couple different composition APIs which can be called from the `setup` function of any of your Vue components that need to do something authentication related. - -#### useMsal - -This API will call `handleRedirectPromise` if it has not yet been called. This is very important if your application uses redirects instead of popups because this is what actually processes the response from your Identity Provider. It should be called at least once per page load before you do anything else related to authentication. If you are using popups as your interaction type, this is not needed. - -This API also returns: - -- The `PublicClientApplication` instance which you can use to call any of the [MSAL APIs](https://azuread.github.io/microsoft-authentication-library-for-js/ref/interfaces/_azure_msal_browser.IPublicClientApplication.html) -- A `ref` indicating what type of interaction is currently in progress. -- A `ref` of the array of accounts currently signed in - -Basic examples of how this can be used can be found in each of the vue components located in `src/components` - -#### useIsAuthenticated - -Returns a `ref` indicating if a user is signed-in or not. The implementation in this sample says that a user is signed in if at least 1 account is present in the account array. More complex use cases may require a different implementation. - -One example of how this could be used can be found in `src/components/NavBar.vue`. It is used as the condition for the `v-if` directive to conditionally render a Sign In or Sign Out button depending on the sign-in state of the user. This is reactive and will update as soon as the user signs in or out. - -```vue - - - -``` - -#### useMsalAuthentication - -Will attempt to silently acquire a token and fallback to interaction if no user is signed in or silent acquisition fails. This can be used instead of a route guard to protect components. - -You must provide: - -- Your preferred interaction type (Popup or Redirect) to be used in case the request cannot be completed silently -- The auth request that will be used to acquire the token. You can find the request/response types [here](https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/request-response-object.md) - -Returns: - -- A `ref` of the `AuthenticationResult` object containing the accessToken and idToken, among other things. The full response object can be found [here](https://azuread.github.io/microsoft-authentication-library-for-js/ref/modules/_azure_msal_common.html#authenticationresult) -- An `acquireToken` function that can be called from your Vue component when a new token is needed or to recover from an error. The other return values will be updated when this function is invoked. -- A `ref` of the error object if the token request failed for any reason -- An `ref` indicating if this instance of `useMsalAuthentication` is currently acquiring a token. (Note this is different from the inProgress value returned by `useMsal` which represents only interaction and is global) - -Usage of this is demonstrated on the `/profilenoguard` route located in `src/views/ProfileNoGuard.vue`. A generic example can be seen below: - -```vue - - - -``` - -### Integrating with vue-router - -This sample demonstrates integration with the official router for vue: `vue-router`. The concepts here may also be relevant to other 3rd party routers, but the implementations may differ. - -#### Configuring MSAL to use the router for route changes - -When MSAL.js needs to change routes, such as when returning the user to the page they were trying to get to from the `redirectUri`, it will by default reassign `window.location`. This can be a problem when using routers because it will trigger a full page refresh, rerendering the entire page, which is not always desired. To take advantage of the benefits routers provide MSAL.js exposes an API called `setNavigationClient` which allows you to override the methods used to perform navigation. - -An example navigation client for `vue-router` can be found in `src/router/NavigationClient.ts`. You'll also find the following 2 lines in `main.ts` which provides this custom navigation client to MSAL.js: - -```javascript -const navigationClient = new CustomNavigationClient(router); -msalInstance.setNavigationClient(navigationClient); -``` - -#### Guarding routes - -This sample also demonstrates how to write a global route guard if your application uses the `vue-router` package to handle routing. - -In the router configuration, located in `src/router/router.ts`, we register the route we want to protect with a `meta.requiresAuth` property, like so: - -```javascript -const routes = [ - { - path: "/profile", - name: "Profile", - component: Profile, - meta: { - requiresAuth: true, - }, - }, -]; -``` - -Then we register a global route guard, as shown in `src/router/Guard.ts`. A similar approach can be taken for [per route guards](https://router.vuejs.org/guide/advanced/navigation-guards.html#per-route-guard) instead, if desired. diff --git a/samples/msal-browser-samples/vue3-sample-app/index.html b/samples/msal-browser-samples/vue3-sample-app/index.html deleted file mode 100644 index 29c0dd4419..0000000000 --- a/samples/msal-browser-samples/vue3-sample-app/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - MSAL-Vue Sample - - -
- - - diff --git a/samples/msal-browser-samples/vue3-sample-app/package.json b/samples/msal-browser-samples/vue3-sample-app/package.json deleted file mode 100644 index 62643b78f6..0000000000 --- a/samples/msal-browser-samples/vue3-sample-app/package.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "msal-vue-sample", - "version": "0.0.0", - "scripts": { - "start": "vite", - "build": "vue-tsc --noEmit && vite build", - "serve": "vite preview", - "build:package": "cd ../../../lib/msal-browser && npm run build:all" - }, - "dependencies": { - "@azure/msal-browser": "^5.0.0-alpha.0", - "element-plus": "^2.2.19", - "vue": "^3.2.41", - "vue-router": "^4.1.5" - }, - "devDependencies": { - "@vitejs/plugin-vue": "^4.6.2", - "typescript": "^4.8.4", - "vite": "^4.5.14", - "vue-tsc": "^1.0.8" - } -} diff --git a/samples/msal-browser-samples/vue3-sample-app/public/favicon.ico b/samples/msal-browser-samples/vue3-sample-app/public/favicon.ico deleted file mode 100644 index df36fcfb72584e00488330b560ebcf34a41c64c2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4286 zcmds*O-Phc6o&64GDVCEQHxsW(p4>LW*W<827=Unuo8sGpRux(DN@jWP-e29Wl%wj zY84_aq9}^Am9-cWTD5GGEo#+5Fi2wX_P*bo+xO!)p*7B;iKlbFd(U~_d(U?#hLj56 zPhFkj-|A6~Qk#@g^#D^U0XT1cu=c-vu1+SElX9NR;kzAUV(q0|dl0|%h|dI$%VICy zJnu2^L*Te9JrJMGh%-P79CL0}dq92RGU6gI{v2~|)p}sG5x0U*z<8U;Ij*hB9z?ei z@g6Xq-pDoPl=MANPiR7%172VA%r)kevtV-_5H*QJKFmd;8yA$98zCxBZYXTNZ#QFk2(TX0;Y2dt&WitL#$96|gJY=3xX zpCoi|YNzgO3R`f@IiEeSmKrPSf#h#Qd<$%Ej^RIeeYfsxhPMOG`S`Pz8q``=511zm zAm)MX5AV^5xIWPyEu7u>qYs?pn$I4nL9J!=K=SGlKLXpE<5x+2cDTXq?brj?n6sp= zphe9;_JHf40^9~}9i08r{XM$7HB!`{Ys~TK0kx<}ZQng`UPvH*11|q7&l9?@FQz;8 zx!=3<4seY*%=OlbCbcae?5^V_}*K>Uo6ZWV8mTyE^B=DKy7-sdLYkR5Z?paTgK-zyIkKjIcpyO z{+uIt&YSa_$QnN_@t~L014dyK(fOOo+W*MIxbA6Ndgr=Y!f#Tokqv}n<7-9qfHkc3 z=>a|HWqcX8fzQCT=dqVbogRq!-S>H%yA{1w#2Pn;=e>JiEj7Hl;zdt-2f+j2%DeVD zsW0Ab)ZK@0cIW%W7z}H{&~yGhn~D;aiP4=;m-HCo`BEI+Kd6 z={Xwx{TKxD#iCLfl2vQGDitKtN>z|-AdCN|$jTFDg0m3O`WLD4_s#$S diff --git a/samples/msal-browser-samples/vue3-sample-app/src/App.vue b/samples/msal-browser-samples/vue3-sample-app/src/App.vue deleted file mode 100644 index abe827a35b..0000000000 --- a/samples/msal-browser-samples/vue3-sample-app/src/App.vue +++ /dev/null @@ -1,28 +0,0 @@ - - - - - diff --git a/samples/msal-browser-samples/vue3-sample-app/src/assets/logo.png b/samples/msal-browser-samples/vue3-sample-app/src/assets/logo.png deleted file mode 100644 index f3d2503fc2a44b5053b0837ebea6e87a2d339a43..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6849 zcmaKRcUV(fvo}bjDT-7nLI_nlK}sT_69H+`qzVWDA|yaU?}j417wLi^B1KB1SLsC& zL0ag7$U(XW5YR7p&Ux?sP$d4lvMt8C^+TcQu4F zQqv!UF!I+kw)c0jhd6+g6oCr9P?7)?!qX1ui*iL{p}sKCAGuJ{{W)0z1pLF|=>h}& zt(2Lr0Z`2ig8<5i%Zk}cO5Fm=LByqGWaS`oqChZdEFmc`0hSb#gg|Aap^{+WKOYcj zHjINK)KDG%&s?Mt4CL(T=?;~U@bU2x_mLKN!#GJuK_CzbNw5SMEJorG!}_5;?R>@1 zSl)jns3WlU7^J%=(hUtfmuUCU&C3%8B5C^f5>W2Cy8jW3#{Od{lF1}|?c61##3dzA zsPlFG;l_FzBK}8>|H_Ru_H#!_7$UH4UKo3lKOA}g1(R&|e@}GINYVzX?q=_WLZCgh z)L|eJMce`D0EIwgRaNETDsr+?vQknSGAi=7H00r`QnI%oQnFxm`G2umXso9l+8*&Q z7WqF|$p49js$mdzo^BXpH#gURy=UO;=IMrYc5?@+sR4y_?d*~0^YP7d+y0{}0)zBM zIKVM(DBvICK#~7N0a+PY6)7;u=dutmNqK3AlsrUU9U`d;msiucB_|8|2kY=(7XA;G zwDA8AR)VCA#JOkxm#6oHNS^YVuOU;8p$N)2{`;oF|rQ?B~K$%rHDxXs+_G zF5|-uqHZvSzq}L;5Kcy_P+x0${33}Ofb6+TX&=y;;PkEOpz%+_bCw_{<&~ zeLV|!bP%l1qxywfVr9Z9JI+++EO^x>ZuCK);=$VIG1`kxK8F2M8AdC$iOe3cj1fo(ce4l-9 z7*zKy3={MixvUk=enQE;ED~7tv%qh&3lR<0m??@w{ILF|e#QOyPkFYK!&Up7xWNtL zOW%1QMC<3o;G9_S1;NkPB6bqbCOjeztEc6TsBM<(q9((JKiH{01+Ud=uw9B@{;(JJ z-DxI2*{pMq`q1RQc;V8@gYAY44Z!%#W~M9pRxI(R?SJ7sy7em=Z5DbuDlr@*q|25V)($-f}9c#?D%dU^RS<(wz?{P zFFHtCab*!rl(~j@0(Nadvwg8q|4!}L^>d?0al6}Rrv9$0M#^&@zjbfJy_n!%mVHK4 z6pLRIQ^Uq~dnyy$`ay51Us6WaP%&O;@49m&{G3z7xV3dLtt1VTOMYl3UW~Rm{Eq4m zF?Zl_v;?7EFx1_+#WFUXxcK78IV)FO>42@cm@}2I%pVbZqQ}3;p;sDIm&knay03a^ zn$5}Q$G!@fTwD$e(x-~aWP0h+4NRz$KlnO_H2c< z(XX#lPuW_%H#Q+c&(nRyX1-IadKR-%$4FYC0fsCmL9ky3 zKpxyjd^JFR+vg2!=HWf}2Z?@Td`0EG`kU?{8zKrvtsm)|7>pPk9nu@2^z96aU2<#` z2QhvH5w&V;wER?mopu+nqu*n8p~(%QkwSs&*0eJwa zMXR05`OSFpfyRb!Y_+H@O%Y z0=K^y6B8Gcbl?SA)qMP3Z+=C(?8zL@=74R=EVnE?vY!1BQy2@q*RUgRx4yJ$k}MnL zs!?74QciNb-LcG*&o<9=DSL>1n}ZNd)w1z3-0Pd^4ED1{qd=9|!!N?xnXjM!EuylY z5=!H>&hSofh8V?Jofyd!h`xDI1fYAuV(sZwwN~{$a}MX^=+0TH*SFp$vyxmUv7C*W zv^3Gl0+eTFgBi3FVD;$nhcp)ka*4gSskYIqQ&+M}xP9yLAkWzBI^I%zR^l1e?bW_6 zIn{mo{dD=)9@V?s^fa55jh78rP*Ze<3`tRCN4*mpO$@7a^*2B*7N_|A(Ve2VB|)_o z$=#_=aBkhe(ifX}MLT()@5?OV+~7cXC3r!%{QJxriXo9I%*3q4KT4Xxzyd{ z9;_%=W%q!Vw$Z7F3lUnY+1HZ*lO;4;VR2+i4+D(m#01OYq|L_fbnT;KN<^dkkCwtd zF7n+O7KvAw8c`JUh6LmeIrk4`F3o|AagKSMK3))_5Cv~y2Bb2!Ibg9BO7Vkz?pAYX zoI=B}+$R22&IL`NCYUYjrdhwjnMx_v=-Qcx-jmtN>!Zqf|n1^SWrHy zK|MwJ?Z#^>)rfT5YSY{qjZ&`Fjd;^vv&gF-Yj6$9-Dy$<6zeP4s+78gS2|t%Z309b z0^fp~ue_}i`U9j!<|qF92_3oB09NqgAoehQ`)<)dSfKoJl_A6Ec#*Mx9Cpd-p#$Ez z={AM*r-bQs6*z$!*VA4|QE7bf@-4vb?Q+pPKLkY2{yKsw{&udv_2v8{Dbd zm~8VAv!G~s)`O3|Q6vFUV%8%+?ZSVUa(;fhPNg#vab@J*9XE4#D%)$UU-T5`fwjz! z6&gA^`OGu6aUk{l*h9eB?opVdrHK>Q@U>&JQ_2pR%}TyOXGq_6s56_`U(WoOaAb+K zXQr#6H}>a-GYs9^bGP2Y&hSP5gEtW+GVC4=wy0wQk=~%CSXj=GH6q z-T#s!BV`xZVxm{~jr_ezYRpqqIcXC=Oq`b{lu`Rt(IYr4B91hhVC?yg{ol4WUr3v9 zOAk2LG>CIECZ-WIs0$N}F#eoIUEtZudc7DPYIjzGqDLWk_A4#(LgacooD z2K4IWs@N`Bddm-{%oy}!k0^i6Yh)uJ1S*90>|bm3TOZxcV|ywHUb(+CeX-o1|LTZM zwU>dY3R&U)T(}5#Neh?-CWT~@{6Ke@sI)uSuzoah8COy)w)B)aslJmp`WUcjdia-0 zl2Y}&L~XfA`uYQboAJ1;J{XLhYjH){cObH3FDva+^8ioOQy%Z=xyjGLmWMrzfFoH; zEi3AG`_v+%)&lDJE;iJWJDI@-X9K5O)LD~j*PBe(wu+|%ar~C+LK1+-+lK=t# z+Xc+J7qp~5q=B~rD!x78)?1+KUIbYr^5rcl&tB-cTtj+e%{gpZZ4G~6r15+d|J(ky zjg@@UzMW0k9@S#W(1H{u;Nq(7llJbq;;4t$awM;l&(2s+$l!Ay9^Ge|34CVhr7|BG z?dAR83smef^frq9V(OH+a+ki#q&-7TkWfFM=5bsGbU(8mC;>QTCWL5ydz9s6k@?+V zcjiH`VI=59P-(-DWXZ~5DH>B^_H~;4$)KUhnmGo*G!Tq8^LjfUDO)lASN*=#AY_yS zqW9UX(VOCO&p@kHdUUgsBO0KhXxn1sprK5h8}+>IhX(nSXZKwlNsjk^M|RAaqmCZB zHBolOHYBas@&{PT=R+?d8pZu zUHfyucQ`(umXSW7o?HQ3H21M`ZJal+%*)SH1B1j6rxTlG3hx1IGJN^M7{$j(9V;MZ zRKybgVuxKo#XVM+?*yTy{W+XHaU5Jbt-UG33x{u(N-2wmw;zzPH&4DE103HV@ER86 z|FZEmQb|&1s5#`$4!Cm}&`^{(4V}OP$bk`}v6q6rm;P!H)W|2i^e{7lTk2W@jo_9q z*aw|U7#+g59Fv(5qI`#O-qPj#@_P>PC#I(GSp3DLv7x-dmYK=C7lPF8a)bxb=@)B1 zUZ`EqpXV2dR}B&r`uM}N(TS99ZT0UB%IN|0H%DcVO#T%L_chrgn#m6%x4KE*IMfjX zJ%4veCEqbXZ`H`F_+fELMC@wuy_ch%t*+Z+1I}wN#C+dRrf2X{1C8=yZ_%Pt6wL_~ zZ2NN-hXOT4P4n$QFO7yYHS-4wF1Xfr-meG9Pn;uK51?hfel`d38k{W)F*|gJLT2#T z<~>spMu4(mul-8Q3*pf=N4DcI)zzjqAgbE2eOT7~&f1W3VsdD44Ffe;3mJp-V@8UC z)|qnPc12o~$X-+U@L_lWqv-RtvB~%hLF($%Ew5w>^NR82qC_0FB z)=hP1-OEx?lLi#jnLzH}a;Nvr@JDO-zQWd}#k^an$Kwml;MrD&)sC5b`s0ZkVyPkb zt}-jOq^%_9>YZe7Y}PhW{a)c39G`kg(P4@kxjcYfgB4XOOcmezdUI7j-!gs7oAo2o zx(Ph{G+YZ`a%~kzK!HTAA5NXE-7vOFRr5oqY$rH>WI6SFvWmahFav!CfRMM3%8J&c z*p+%|-fNS_@QrFr(at!JY9jCg9F-%5{nb5Bo~z@Y9m&SHYV`49GAJjA5h~h4(G!Se zZmK{Bo7ivCfvl}@A-ptkFGcWXAzj3xfl{evi-OG(TaCn1FAHxRc{}B|x+Ua1D=I6M z!C^ZIvK6aS_c&(=OQDZfm>O`Nxsw{ta&yiYPA~@e#c%N>>#rq)k6Aru-qD4(D^v)y z*>Rs;YUbD1S8^D(ps6Jbj0K3wJw>L4m)0e(6Pee3Y?gy9i0^bZO?$*sv+xKV?WBlh zAp*;v6w!a8;A7sLB*g-^<$Z4L7|5jXxxP1}hQZ<55f9<^KJ>^mKlWSGaLcO0=$jem zWyZkRwe~u{{tU63DlCaS9$Y4CP4f?+wwa(&1ou)b>72ydrFvm`Rj-0`kBJgK@nd(*Eh!(NC{F-@=FnF&Y!q`7){YsLLHf0_B6aHc# z>WIuHTyJwIH{BJ4)2RtEauC7Yq7Cytc|S)4^*t8Va3HR zg=~sN^tp9re@w=GTx$;zOWMjcg-7X3Wk^N$n;&Kf1RgVG2}2L-(0o)54C509C&77i zrjSi{X*WV=%C17((N^6R4Ya*4#6s_L99RtQ>m(%#nQ#wrRC8Y%yxkH;d!MdY+Tw@r zjpSnK`;C-U{ATcgaxoEpP0Gf+tx);buOMlK=01D|J+ROu37qc*rD(w`#O=3*O*w9?biwNoq3WN1`&Wp8TvKj3C z3HR9ssH7a&Vr<6waJrU zdLg!ieYz%U^bmpn%;(V%%ugMk92&?_XX1K@mwnVSE6!&%P%Wdi7_h`CpScvspMx?N zQUR>oadnG17#hNc$pkTp+9lW+MBKHRZ~74XWUryd)4yd zj98$%XmIL4(9OnoeO5Fnyn&fpQ9b0h4e6EHHw*l68j;>(ya`g^S&y2{O8U>1*>4zR zq*WSI_2o$CHQ?x0!wl9bpx|Cm2+kFMR)oMud1%n2=qn5nE&t@Fgr#=Zv2?}wtEz^T z9rrj=?IH*qI5{G@Rn&}^Z{+TW}mQeb9=8b<_a`&Cm#n%n~ zU47MvCBsdXFB1+adOO)03+nczfWa#vwk#r{o{dF)QWya9v2nv43Zp3%Ps}($lA02*_g25t;|T{A5snSY?3A zrRQ~(Ygh_ebltHo1VCbJb*eOAr;4cnlXLvI>*$-#AVsGg6B1r7@;g^L zFlJ_th0vxO7;-opU@WAFe;<}?!2q?RBrFK5U{*ai@NLKZ^};Ul}beukveh?TQn;$%9=R+DX07m82gP$=}Uo_%&ngV`}Hyv8g{u z3SWzTGV|cwQuFIs7ZDOqO_fGf8Q`8MwL}eUp>q?4eqCmOTcwQuXtQckPy|4F1on8l zP*h>d+cH#XQf|+6c|S{7SF(Lg>bR~l(0uY?O{OEVlaxa5@e%T&xju=o1`=OD#qc16 zSvyH*my(dcp6~VqR;o(#@m44Lug@~_qw+HA=mS#Z^4reBy8iV?H~I;{LQWk3aKK8$bLRyt$g?- { - if (containsPii) { - return; - } - switch (level) { - case LogLevel.Error: - console.error(message); - return; - case LogLevel.Info: - console.info(message); - return; - case LogLevel.Verbose: - console.debug(message); - return; - case LogLevel.Warning: - console.warn(message); - return; - default: - return; - } - }, - logLevel: LogLevel.Verbose - } - } -}; - -export const msalInstance = new PublicClientApplication(msalConfig); - -// Add here scopes for id token to be used at MS Identity Platform endpoints. -export const loginRequest = { - scopes: ['User.Read'], -}; - -// Add here the endpoints for MS Graph API services you would like to use. -export const graphConfig = { - graphMeEndpoint: 'https://graph.microsoft.com/v1.0/me', -}; diff --git a/samples/msal-browser-samples/vue3-sample-app/src/components/NavBar.vue b/samples/msal-browser-samples/vue3-sample-app/src/components/NavBar.vue deleted file mode 100644 index a73a6f933f..0000000000 --- a/samples/msal-browser-samples/vue3-sample-app/src/components/NavBar.vue +++ /dev/null @@ -1,35 +0,0 @@ - - - - - \ No newline at end of file diff --git a/samples/msal-browser-samples/vue3-sample-app/src/components/SignInButton.vue b/samples/msal-browser-samples/vue3-sample-app/src/components/SignInButton.vue deleted file mode 100644 index df1b8c7461..0000000000 --- a/samples/msal-browser-samples/vue3-sample-app/src/components/SignInButton.vue +++ /dev/null @@ -1,26 +0,0 @@ - - - diff --git a/samples/msal-browser-samples/vue3-sample-app/src/components/SignOutButton.vue b/samples/msal-browser-samples/vue3-sample-app/src/components/SignOutButton.vue deleted file mode 100644 index bcfa6ad9c5..0000000000 --- a/samples/msal-browser-samples/vue3-sample-app/src/components/SignOutButton.vue +++ /dev/null @@ -1,28 +0,0 @@ - - - diff --git a/samples/msal-browser-samples/vue3-sample-app/src/components/WelcomeName.vue b/samples/msal-browser-samples/vue3-sample-app/src/components/WelcomeName.vue deleted file mode 100644 index 296d06570c..0000000000 --- a/samples/msal-browser-samples/vue3-sample-app/src/components/WelcomeName.vue +++ /dev/null @@ -1,29 +0,0 @@ - - - - - diff --git a/samples/msal-browser-samples/vue3-sample-app/src/composition-api/useIsAuthenticated.ts b/samples/msal-browser-samples/vue3-sample-app/src/composition-api/useIsAuthenticated.ts deleted file mode 100644 index a47cd291bf..0000000000 --- a/samples/msal-browser-samples/vue3-sample-app/src/composition-api/useIsAuthenticated.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Ref, ref, watch } from "vue"; -import { useMsal } from "./useMsal"; - -export function useIsAuthenticated(): Ref { - const { accounts } = useMsal(); - const isAuthenticated = ref(accounts.value.length > 0); - - watch(accounts, () => { - isAuthenticated.value = accounts.value.length > 0; - }); - - return isAuthenticated; -} \ No newline at end of file diff --git a/samples/msal-browser-samples/vue3-sample-app/src/composition-api/useMsal.ts b/samples/msal-browser-samples/vue3-sample-app/src/composition-api/useMsal.ts deleted file mode 100644 index 583b039505..0000000000 --- a/samples/msal-browser-samples/vue3-sample-app/src/composition-api/useMsal.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { AccountInfo, InteractionStatus, PublicClientApplication } from "@azure/msal-browser"; -import { getCurrentInstance, Ref, toRefs } from "vue"; - -export type MsalContext = { - instance: PublicClientApplication, - accounts: Ref, - inProgress: Ref -} - -export function useMsal(): MsalContext { - const internalInstance = getCurrentInstance(); - if (!internalInstance) { - throw "useMsal() cannot be called outside the setup() function of a component"; - } - const { instance, accounts, inProgress} = toRefs(internalInstance.appContext.config.globalProperties.$msal); - - if (!instance || !accounts || !inProgress) { - throw "Please install the msalPlugin"; - } - - if (inProgress.value === InteractionStatus.Startup) { - instance.value.initialize().then(() => { - instance.value.handleRedirectPromise().catch(() => { - // Errors should be handled by listening to the ACQUIRE_TOKEN_FAILURE event - return; - }); - }); - } - - return { - instance: instance.value, - accounts, - inProgress - } -} \ No newline at end of file diff --git a/samples/msal-browser-samples/vue3-sample-app/src/composition-api/useMsalAuthentication.ts b/samples/msal-browser-samples/vue3-sample-app/src/composition-api/useMsalAuthentication.ts deleted file mode 100644 index ffbe1d3cfa..0000000000 --- a/samples/msal-browser-samples/vue3-sample-app/src/composition-api/useMsalAuthentication.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { AuthenticationResult, AuthError, InteractionStatus, InteractionType, PopupRequest, RedirectRequest, SilentRequest } from "@azure/msal-browser"; -import { Ref, ref, watch } from "vue"; -import { useMsal } from "./useMsal"; - -export type MsalAuthenticationResult = { - acquireToken: (requestOverride?: PopupRequest|RedirectRequest|SilentRequest) => Promise; - result: Ref; - error: Ref; - inProgress: Ref; -} - -export function useMsalAuthentication(interactionType: InteractionType, request: PopupRequest|RedirectRequest|SilentRequest): MsalAuthenticationResult { - const { instance, inProgress } = useMsal(); - - const localInProgress = ref(false); - const result = ref(null); - const error = ref(null); - - const acquireToken = async (requestOverride?: PopupRequest|RedirectRequest|SilentRequest) => { - if (!localInProgress.value) { - localInProgress.value = true; - const tokenRequest = requestOverride || request; - - if (inProgress.value === InteractionStatus.Startup || inProgress.value === InteractionStatus.HandleRedirect) { - try { - const response = await instance.handleRedirectPromise() - if (response) { - result.value = response; - error.value = null; - return; - } - } catch (e) { - result.value = null; - error.value = e as AuthError; - return; - }; - } - - try { - const response = await instance.acquireTokenSilent(tokenRequest); - result.value = response; - error.value = null; - } catch(e) { - if (inProgress.value !== InteractionStatus.None) { - return; - } - - if (interactionType === InteractionType.Popup) { - instance.loginPopup(tokenRequest).then((response) => { - result.value = response; - error.value = null; - }).catch((e) => { - error.value = e; - result.value = null; - }); - } else if (interactionType === InteractionType.Redirect) { - await instance.loginRedirect(tokenRequest).catch((e) => { - error.value = e; - result.value = null; - }); - } - }; - localInProgress.value = false; - } - } - - const stopWatcher = watch(inProgress, () => { - if (!result.value && !error.value) { - acquireToken(); - } else { - stopWatcher(); - } - }); - - acquireToken(); - - return { - acquireToken, - result, - error, - inProgress: localInProgress - } -} diff --git a/samples/msal-browser-samples/vue3-sample-app/src/env.d.ts b/samples/msal-browser-samples/vue3-sample-app/src/env.d.ts deleted file mode 100644 index d27eb5a311..0000000000 --- a/samples/msal-browser-samples/vue3-sample-app/src/env.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -/// - -declare module '*.vue' { - import { DefineComponent } from 'vue' - // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types - const component: DefineComponent<{}, {}, any> - export default component -} diff --git a/samples/msal-browser-samples/vue3-sample-app/src/main.ts b/samples/msal-browser-samples/vue3-sample-app/src/main.ts deleted file mode 100644 index bab13295ed..0000000000 --- a/samples/msal-browser-samples/vue3-sample-app/src/main.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { createApp } from 'vue'; -import App from './App.vue'; -import router from './router/router'; -import ElementPlus from 'element-plus'; -import 'element-plus/dist/index.css'; -import { msalPlugin } from "./plugins/msalPlugin"; -import { msalInstance } from "./authConfig"; -import { AuthenticationResult, EventType } from "@azure/msal-browser"; -import { CustomNavigationClient } from "./router/NavigationClient"; - -// The next 2 lines are optional. This is how you configure MSAL to take advantage of the router's navigate functions when MSAL redirects between pages in your app -const navigationClient = new CustomNavigationClient(router); -msalInstance.setNavigationClient(navigationClient); - -// Account selection logic is app dependent. Adjust as needed for different use cases. -const accounts = msalInstance.getAllAccounts(); -if (accounts.length > 0) { - msalInstance.setActiveAccount(accounts[0]); -} -msalInstance.addEventCallback((event) => { - if (event.eventType === EventType.LOGIN_SUCCESS && event.payload) { - const payload = event.payload as AuthenticationResult; - const account = payload.account; - msalInstance.setActiveAccount(account); - } -}); - -const app = createApp(App); - -app.use(ElementPlus); -app.use(router); -app.use(msalPlugin, msalInstance); -router.isReady().then(() => { - // Waiting for the router to be ready prevents race conditions when returning from a loginRedirect or acquireTokenRedirect - app.mount('#app'); -}); diff --git a/samples/msal-browser-samples/vue3-sample-app/src/plugins/msalPlugin.ts b/samples/msal-browser-samples/vue3-sample-app/src/plugins/msalPlugin.ts deleted file mode 100644 index 2c3bb3a42a..0000000000 --- a/samples/msal-browser-samples/vue3-sample-app/src/plugins/msalPlugin.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { App, reactive } from "vue"; -import { EventMessage, EventMessageUtils, EventType, InteractionStatus, PublicClientApplication, AccountInfo } from "@azure/msal-browser"; - -type AccountIdentifiers = Partial>; - -/** - * Helper function to determine whether 2 arrays are equal - * Used to avoid unnecessary state updates - * @param arrayA - * @param arrayB - */ -function accountArraysAreEqual(arrayA: Array, arrayB: Array): boolean { - if (arrayA.length !== arrayB.length) { - return false; - } - - const comparisonArray = [...arrayB]; - - return arrayA.every((elementA) => { - const elementB = comparisonArray.shift(); - if (!elementA || !elementB) { - return false; - } - - return (elementA.homeAccountId === elementB.homeAccountId) && - (elementA.localAccountId === elementB.localAccountId) && - (elementA.username === elementB.username); - }); -} - -export const msalPlugin = { - install: (app: App, msalInstance: PublicClientApplication) => { - - const inProgress = InteractionStatus.Startup; - const accounts = msalInstance.getAllAccounts(); - - const state = reactive<{ - instance: PublicClientApplication - inProgress: InteractionStatus - accounts: AccountInfo[] - }>({ - instance: msalInstance, - inProgress: inProgress, - accounts: accounts - }); - - app.config.globalProperties.$msal = state; - - msalInstance.addEventCallback((message: EventMessage) => { - switch (message.eventType) { - case EventType.LOGIN_SUCCESS: - case EventType.LOGOUT_SUCCESS: - case EventType.HANDLE_REDIRECT_END: - case EventType.LOGOUT_END: - case EventType.ACQUIRE_TOKEN_SUCCESS: - case EventType.ACQUIRE_TOKEN_FAILURE: { - const currentAccounts = msalInstance.getAllAccounts(); - if (!accountArraysAreEqual(currentAccounts, state.accounts)) { - state.accounts = currentAccounts; - } - break; - } - } - - const status = EventMessageUtils.getInteractionStatusFromEvent(message, state.inProgress); - if (status !== null) { - state.inProgress = status; - } - }); - } -} diff --git a/samples/msal-browser-samples/vue3-sample-app/src/router/Guard.ts b/samples/msal-browser-samples/vue3-sample-app/src/router/Guard.ts deleted file mode 100644 index 08500c74dd..0000000000 --- a/samples/msal-browser-samples/vue3-sample-app/src/router/Guard.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { RouteLocationNormalized, Router } from "vue-router"; -import { msalInstance, loginRequest } from "../authConfig"; -import { InteractionType, PopupRequest, PublicClientApplication, RedirectRequest } from "@azure/msal-browser"; - -export function registerGuard(router: Router) { - router.beforeEach(async (to: RouteLocationNormalized, from: RouteLocationNormalized) => { - if (to.meta.requiresAuth) { - const request = { - ...loginRequest, - redirectStartPage: to.fullPath - } - const shouldProceed = await isAuthenticated(msalInstance, InteractionType.Redirect, request); - return shouldProceed || '/failed'; - } - - return true; - }); -} - -export async function isAuthenticated(instance: PublicClientApplication, interactionType: InteractionType, loginRequest: PopupRequest|RedirectRequest): Promise { - // If your application uses redirects for interaction, handleRedirectPromise must be called and awaited on each page load before determining if a user is signed in or not - return instance.handleRedirectPromise().then(() => { - const accounts = instance.getAllAccounts(); - if (accounts.length > 0) { - return true; - } - - // User is not signed in and attempting to access protected route. Sign them in. - if (interactionType === InteractionType.Popup) { - return instance.loginPopup(loginRequest).then(() => { - return true; - }).catch(() => { - return false; - }) - } else if (interactionType === InteractionType.Redirect) { - return instance.loginRedirect(loginRequest).then(() => { - return true; - }).catch(() => { - return false; - }); - } - - return false; - }).catch(() => { - return false; - }); -} \ No newline at end of file diff --git a/samples/msal-browser-samples/vue3-sample-app/src/router/NavigationClient.ts b/samples/msal-browser-samples/vue3-sample-app/src/router/NavigationClient.ts deleted file mode 100644 index 58c3a6b33a..0000000000 --- a/samples/msal-browser-samples/vue3-sample-app/src/router/NavigationClient.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { NavigationClient, NavigationOptions } from "@azure/msal-browser"; -import { Router } from "vue-router"; - -/** - * This is an example for overriding the default function MSAL uses to navigate to other urls in your webpage - */ -export class CustomNavigationClient extends NavigationClient{ - private router: Router; - - constructor(router: Router) { - super(); - this.router = router; - } - - /** - * Navigates to other pages within the same web application - * You can use the useHistory hook provided by react-router-dom to take advantage of client-side routing - * @param url - * @param options - */ - async navigateInternal(url: string, options: NavigationOptions) { - const relativePath = url.replace(window.location.origin, ''); - if (options.noHistory) { - this.router.replace(relativePath); - } else { - this.router.push(relativePath); - } - - return false; - } -} diff --git a/samples/msal-browser-samples/vue3-sample-app/src/router/router.ts b/samples/msal-browser-samples/vue3-sample-app/src/router/router.ts deleted file mode 100644 index c7d369ece3..0000000000 --- a/samples/msal-browser-samples/vue3-sample-app/src/router/router.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'; -import Home from '../views/Home.vue'; -import Profile from '../views/Profile.vue'; -import ProfileNoGuard from '../views/ProfileNoGuard.vue'; -import Failed from "../views/Failed.vue"; -import { registerGuard } from "./Guard"; - -const routes: Array = [ - { - path: '/', - name: 'Home', - component: Home, - }, - { - path: '/profile', - name: 'Profile', - component: Profile, - meta: { - requiresAuth: true - } - }, - { - path: '/profileNoGuard', - name: 'ProfileNoGuard', - component: ProfileNoGuard - }, - { - path: '/failed', - name: 'Failed', - component: Failed - } -]; - -const router = createRouter({ - history: createWebHistory(), - routes, -}); - -registerGuard(router); - -export default router; diff --git a/samples/msal-browser-samples/vue3-sample-app/src/utils/MsGraphApiCall.ts b/samples/msal-browser-samples/vue3-sample-app/src/utils/MsGraphApiCall.ts deleted file mode 100644 index 88fafb0e07..0000000000 --- a/samples/msal-browser-samples/vue3-sample-app/src/utils/MsGraphApiCall.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { graphConfig } from "../authConfig"; - -export async function callMsGraph(accessToken: string) { - const headers = new Headers(); - const bearer = `Bearer ${accessToken}`; - - headers.append("Authorization", bearer); - - const options = { - method: "GET", - headers: headers - }; - - return fetch(graphConfig.graphMeEndpoint, options) - .then(response => response.json()) - .catch(error => { - console.log(error); - throw error; - }); -} diff --git a/samples/msal-browser-samples/vue3-sample-app/src/utils/UserInfo.ts b/samples/msal-browser-samples/vue3-sample-app/src/utils/UserInfo.ts deleted file mode 100644 index e2f0bfe4d0..0000000000 --- a/samples/msal-browser-samples/vue3-sample-app/src/utils/UserInfo.ts +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Graph data about the user. - */ -type UserInfo = { - businessPhones?: Array, - displayName?: string, - givenName?: string, - id?: string, - jobTitle?: string, - mail?: string, - mobilePhone?: string, - officeLocation?: string, - preferredLanguage?: string, - surname?: string, - userPrincipalName?: string -}; - -export default UserInfo; diff --git a/samples/msal-browser-samples/vue3-sample-app/src/views/Failed.vue b/samples/msal-browser-samples/vue3-sample-app/src/views/Failed.vue deleted file mode 100644 index f1fb64a782..0000000000 --- a/samples/msal-browser-samples/vue3-sample-app/src/views/Failed.vue +++ /dev/null @@ -1,5 +0,0 @@ - diff --git a/samples/msal-browser-samples/vue3-sample-app/src/views/Home.vue b/samples/msal-browser-samples/vue3-sample-app/src/views/Home.vue deleted file mode 100644 index 3a5bead890..0000000000 --- a/samples/msal-browser-samples/vue3-sample-app/src/views/Home.vue +++ /dev/null @@ -1,19 +0,0 @@ - - - diff --git a/samples/msal-browser-samples/vue3-sample-app/src/views/Profile.vue b/samples/msal-browser-samples/vue3-sample-app/src/views/Profile.vue deleted file mode 100644 index 20e2df990e..0000000000 --- a/samples/msal-browser-samples/vue3-sample-app/src/views/Profile.vue +++ /dev/null @@ -1,52 +0,0 @@ - - - diff --git a/samples/msal-browser-samples/vue3-sample-app/src/views/ProfileNoGuard.vue b/samples/msal-browser-samples/vue3-sample-app/src/views/ProfileNoGuard.vue deleted file mode 100644 index 46627be870..0000000000 --- a/samples/msal-browser-samples/vue3-sample-app/src/views/ProfileNoGuard.vue +++ /dev/null @@ -1,39 +0,0 @@ - - - diff --git a/samples/msal-browser-samples/vue3-sample-app/tsconfig.json b/samples/msal-browser-samples/vue3-sample-app/tsconfig.json deleted file mode 100644 index d50c98460d..0000000000 --- a/samples/msal-browser-samples/vue3-sample-app/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "compilerOptions": { - "skipLibCheck": true, - "target": "esnext", - "useDefineForClassFields": true, - "module": "esnext", - "moduleResolution": "node", - "strict": true, - "jsx": "preserve", - "sourceMap": true, - "resolveJsonModule": true, - "esModuleInterop": true, - "lib": ["esnext", "dom"] - }, - "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/samples/msal-browser-samples/vue3-sample-app/vite.config.ts b/samples/msal-browser-samples/vue3-sample-app/vite.config.ts deleted file mode 100644 index 44b0c30ec8..0000000000 --- a/samples/msal-browser-samples/vue3-sample-app/vite.config.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { defineConfig } from 'vite'; -import vue from '@vitejs/plugin-vue'; -import dns from 'dns'; - -dns.setDefaultResultOrder('verbatim'); - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue()], - server: { - host: 'localhost', - port: 3000, - }, -}) diff --git a/samples/msal-node-samples/ElectronTestApp/.beachballrc b/samples/msal-node-samples/ElectronTestApp/.beachballrc deleted file mode 100644 index eaa7c78ebe..0000000000 --- a/samples/msal-node-samples/ElectronTestApp/.beachballrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "shouldPublish": false -} diff --git a/samples/msal-node-samples/ElectronTestApp/.npmrc b/samples/msal-node-samples/ElectronTestApp/.npmrc deleted file mode 100644 index 43c97e719a..0000000000 --- a/samples/msal-node-samples/ElectronTestApp/.npmrc +++ /dev/null @@ -1 +0,0 @@ -package-lock=false diff --git a/samples/msal-node-samples/ElectronTestApp/README.md b/samples/msal-node-samples/ElectronTestApp/README.md deleted file mode 100644 index 510ec86d36..0000000000 --- a/samples/msal-node-samples/ElectronTestApp/README.md +++ /dev/null @@ -1,157 +0,0 @@ -# MSAL Node Electron Sample - -An Electron application built with TypeScript that uses the MSAL Node library to acquire and store access tokens to authenticate with the Microsoft Graph API. - -> :warning: This sample doesn't follow the best practices for native application authentication using an external user agent for handling the authentication/authorization requests. To follow the best practices, please see the [Electron System Browser Sample](../ElectronSystemBrowserTestApp/README.md). - -## Should I use this sample: - -Understanding the way MSAL Node is used in this sample will help you if you're interested in building an Electron.js application to authenticate and acquire tokens using AzureAD. - -## How to run the samples: - -### Clone this repository - -First, clone the MSAL directory: - -SSH: - -```bash -$ git clone git@github.com:AzureAD/microsoft-authentication-library-for-js.git -``` - -HTTP: - -```bash -$ git clone https://github.com/AzureAD/microsoft-authentication-library-for-js.git -``` - -You can also download the repository as a zip file by selecting "Download ZIP" from the root repository's dropdown "Code" menu. Once you've downloaded the ZIP file, you can decompress it locally and explore the code. - -### Pre-requisites - -- By using MSAL Node, you are working with the Microsoft Identity ecosystem. Read about [App Registrations](https://docs.microsoft.com/en-us/graph/auth-register-app-v2) and register one for use with this code. -- Install [Node.js](https://nodejs.org/en/), [Electron.js](https://www.electronjs.org/) and [TypeScript](https://www.typescriptlang.org/) if needed. -- Install the MSAL Node package: - -```bash -npm install @azure/msal-node -``` - -- If you are customizing or building locally, navigate to the `lib/msal-node` directory and build it using the following command: - -```bash -npm run build:package -``` - -- From the repository's root directory, navigate to the Electron sample application: - -```bash -$ cd samples/msal-node-samples/standalone-samples/ElectronTestApp -``` - -### Configure the application - -The MSAL configuration object in the `ElectronTestApp` is defined in the `AuthProvider.ts` file. However, the configuration values used to build the object are defined in and imported from JSON files in the `config/` directory. The `ElectronTestApp` loads the `config/customConfig.json` configuration by default. You can update the configuration attributes to match your [App Registration](https://docs.microsoft.com/en-us/graph/auth-register-app-v2) directly in the `config/customConfg.json` file, or you can add your own configuration file and change the import path like so: - -AuthProvider.ts - -```javascript -// Change this to load the desired MSAL Client Configuration -import * as APP_CONFIG from "./config/customConfig.json"; // Change this - -import * as APP_CONFIG from "./config/YOUR_CUSTOM_CONFIG_FILE.json"; // To this -``` - -This application uses the `User.Read` and `Mail.Read` Microsoft Graph Scopes, so make sure they are enabled in your App Registration. - -**Note: If you'd like to configure custom scopes for this sample application, you'll need to modify the request scopes used in the `setRequestObjects()` method within `AuthProvider.ts`. ** - -#### Custom File Protocols and Redirect URIs - -To demonstrate best security practices, this Electron sample application makes use of a custom file protocol instead of a regular web (https://) redirect URI in order to handle the redirection step of the authorization flow, as suggested in the [OAuth2.0 specification for Native Apps](https://tools.ietf.org/html/rfc8252#section-7.1). - -The reason this applies to Electron applications (such as this one) is that, although Electron uses Chromium to support browser-based JavaScript, it also has access to operating system resources, which makes it a Public Client Native Application under OAuth 2.0 and requires extra security considerations. - -On the Electron side of this sample application, the name of the custom file protocol ("msal4b0db8c2-9f26-4417-8bde-3f0e3656f8e0" by default) is defind in the `fileProtocol` attribute in the JSON configuration file: - -```json -{ - "authOptions": ..., - "request": ..., - "resourceApi": ..., - "fileProtocol": - { - "name": "msal4b0db8c2-9f26-4417-8bde-3f0e3656f8e0" - } -} -``` - -The way the sample is configured, during authentication, the application will listen for requests and responses to URIs beginning with `"msal4b0db8c2-9f26-4417-8bde-3f0e3656f8e0://"`. - -It is important that protocol in the `redirectUri` property in all the requests matches the file protocol established in the `fileProtocol` attribute, otherwise the `ElectronTestApp` won't be able to listen for redirect responses: - -```json -{ - "authOptions": ..., - "request": - { - "authCodeUrlParameters": { - "scopes": ["user.read"], - "redirectUri": "msal4b0db8c2-9f26-4417-8bde-3f0e3656f8e0://auth" - }, - "authCodeRequest": { - "redirectUri": "msal4b0db8c2-9f26-4417-8bde-3f0e3656f8e0://auth", - "scopes": ["User.Read"] - } - }, - "resourceApi": ..., - "fileProtocol": - { - "name": "msal4b0db8c2-9f26-4417-8bde-3f0e3656f8e0" - } -} -``` - -Both of these values, the `redirectUri` and `fileProtocol` name are arbitrary and can be customized to your preference (ideally they shouldn't be obvious to guess and should follow the suggestions in the [OAuth2.0 specification for Native Apps](https://tools.ietf.org/html/rfc8252#section-8.4) specification). The only thing that matters is that the `redirectUri` is a format that begins with `"CUSTOM_FILE_PROTOCOL_NAME://"` and followed by any path component (required). - -For example, the following pairs of values should work: - -```typescript -/// Ex 1: -const CUSTOM_FILE_PROTOCOL = "msal"; -const redirectUri = "msal://auth"; - -/// Ex 2: -const CUSTOM_FILE_PROTOCOL = "sampleapp"; -const redirectUri = "sampleapp://redirect"; - -/// Ex 3: -const CUSTOM_FILE_PROTOCOL = "com.sampleapp"; -const redirectUri = "com.sampleapp://auth"; -``` - -#### Registering a custom file protocol URI as a Redirect URI - -Whether or not you decide to customize these values, you must register the `redirectUri` in the Microsoft Entra admin center as a Mobile or Desktop Redirect URI. - -1. Go to the App Registration in the Microsoft Entra admin center. -2. Click the `Authentication` tab in the side menu. -3. Under "Platform configurations", click the "Add a platform" link. -4. Select "Mobile and desktop applications". -5. Copy the exact `redirectUri` value (`msal4b0db8c2-9f26-4417-8bde-3f0e3656f8e0://auth` is the default if you don't want to change the configuration) into the input box. -6. Click "Configure" - -### Executing the application - -Once you are in the sample application directory and you've configured the sample application to match your App Registration and registered Redirect URI, you can install all of the dependencies by running: - -```bash -$ npm install -``` - -When the dependencies have been installed, you can run the sample application by using the following command, after which the Electron application should start. - -```bash -$ npm start -``` diff --git a/samples/msal-node-samples/ElectronTestApp/data/cacheTemplate.json b/samples/msal-node-samples/ElectronTestApp/data/cacheTemplate.json deleted file mode 100644 index cc8294c3f7..0000000000 --- a/samples/msal-node-samples/ElectronTestApp/data/cacheTemplate.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "Account": {}, - "IdToken": {}, - "AccessToken": {}, - "RefreshToken": {}, - "AppMetadata": {} - } \ No newline at end of file diff --git a/samples/msal-node-samples/ElectronTestApp/index.html b/samples/msal-node-samples/ElectronTestApp/index.html deleted file mode 100644 index 6d9dfd837b..0000000000 --- a/samples/msal-node-samples/ElectronTestApp/index.html +++ /dev/null @@ -1,64 +0,0 @@ - - - - - - MSAL Node Electron Sample App - - - - - - - -
-
Electron App Calling Microsoft Graph using MSAL Node
-
-
- -
-
-
-
-
-
-
- -
-
-
-
- - - - - - - - - - diff --git a/samples/msal-node-samples/ElectronTestApp/package.json b/samples/msal-node-samples/ElectronTestApp/package.json deleted file mode 100644 index a9e6ef2f86..0000000000 --- a/samples/msal-node-samples/ElectronTestApp/package.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "name": "electron-test-app", - "version": "1.0.0", - "description": "A sample Electron application that uses msal-node to acquire tokens", - "main": "App.ts", - "private": true, - "scripts": { - "build": "tsc", - "start": "npm run build && electron dist/app.js", - "build:package": "cd ../../../lib/msal-common && npm run build && cd ../msal-node && npm run build", - "start:build": "npm run build:package && npm start" - }, - "keywords": [ - "msal-node", - "electron", - "javascript" - ], - "author": "", - "license": "MIT", - "devDependencies": { - "babel": "^6.23.0", - "electron": "^22.3.25", - "typescript": "^4.1.2" - }, - "dependencies": { - "@azure/msal-node": "^3.0.0", - "axios": "^1.9.0" - } -} diff --git a/samples/msal-node-samples/ElectronTestApp/playwright.config.ts b/samples/msal-node-samples/ElectronTestApp/playwright.config.ts deleted file mode 100644 index 39b24a3c05..0000000000 --- a/samples/msal-node-samples/ElectronTestApp/playwright.config.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { PlaywrightTestConfig } from "@playwright/test"; -import * as path from "path"; - -const config: PlaywrightTestConfig = { - testDir: path.join(__dirname, "/test"), - retries: 1, - use: { - trace: "on-first-retry", - }, - timeout: 30000, - globalTimeout: 5400000, - workers: process.env.CI ? 1 : undefined, -}; - -export default config; diff --git a/samples/msal-node-samples/ElectronTestApp/src/App.ts b/samples/msal-node-samples/ElectronTestApp/src/App.ts deleted file mode 100644 index 19b28e1cc1..0000000000 --- a/samples/msal-node-samples/ElectronTestApp/src/App.ts +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License - -import Main from "./Main"; -Main.main(); diff --git a/samples/msal-node-samples/ElectronTestApp/src/AuthCodeListener.ts b/samples/msal-node-samples/ElectronTestApp/src/AuthCodeListener.ts deleted file mode 100644 index 3b9b11e9da..0000000000 --- a/samples/msal-node-samples/ElectronTestApp/src/AuthCodeListener.ts +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -/** - * AuthCodeListener is the base class from which - * special CustomFileProtocol and HttpAuthCode inherit - * their structure and members. - */ -export abstract class AuthCodeListener { - private hostName: string; - - /** - * Constructor - * @param hostName - A string that represents the host name that should be listened on (i.e. 'msal' or '127.0.0.1') - */ - constructor(hostName: string) { - this.hostName = hostName; - } - - public get host(): string { - return this.hostName; - } - - public abstract start(): Promise; - public abstract close(): void; -} diff --git a/samples/msal-node-samples/ElectronTestApp/src/AuthProvider.ts b/samples/msal-node-samples/ElectronTestApp/src/AuthProvider.ts deleted file mode 100644 index 3cc48287f4..0000000000 --- a/samples/msal-node-samples/ElectronTestApp/src/AuthProvider.ts +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. - */ -import { - PublicClientApplication, - LogLevel, - AccountInfo, - AuthorizationCodeRequest, - AuthorizationUrlRequest, - AuthenticationResult, - SilentFlowRequest, - CryptoProvider, -} from "@azure/msal-node"; -import { cachePlugin } from "./CachePlugin"; -import { BrowserWindow } from "electron"; -import { CustomProtocolListener } from "./CustomProtocolListener"; - -export default class AuthProvider { - private clientApplication: PublicClientApplication; - private account: AccountInfo; - private authCodeUrlParams: AuthorizationUrlRequest; - private authCodeRequest: AuthorizationCodeRequest; - private silentProfileRequest: SilentFlowRequest; - private silentMailRequest: SilentFlowRequest; - private authConfig: any; - - constructor(authConfig: any) { - this.authConfig = authConfig; - - this.clientApplication = new PublicClientApplication({ - auth: this.authConfig.authOptions, - cache: { - cachePlugin: cachePlugin(this.authConfig.cache.cacheLocation), - }, - system: { - loggerOptions: { - loggerCallback(loglevel, message, containsPii) { - console.log(message); - }, - piiLoggingEnabled: false, - logLevel: LogLevel.Info, - }, - }, - }); - - this.account = null; - this.setRequestObjects(); - } - - public get currentAccount(): AccountInfo { - return this.account; - } - - // Creates a "popup" window for interactive authentication - private static async createAuthWindow(): Promise { - const popupWindow = new BrowserWindow({ - width: 400, - height: 600, - }); - - // if the app is run by test automation, clear the cache - if (process.env.automation === "1") { - await popupWindow.webContents.session.clearStorageData(); - } - - return popupWindow; - } - - /** - * Initialize request objects used by this AuthModule. - */ - private setRequestObjects(): void { - const baseSilentRequest = { - account: null, - forceRefresh: false, - }; - - this.authCodeUrlParams = this.authConfig.request.authCodeUrlParameters; - - this.authCodeRequest = { - ...this.authConfig.request.authCodeRequest, - code: null, - }; - - this.silentProfileRequest = { - ...baseSilentRequest, - scopes: ["User.Read"], - }; - - this.silentMailRequest = { - ...baseSilentRequest, - scopes: ["Mail.Read"], - }; - } - - async getProfileToken(): Promise { - return await this.getToken(this.silentProfileRequest); - } - - async getMailToken(): Promise { - return await this.getToken(this.silentMailRequest); - } - - async getToken(request: SilentFlowRequest): Promise { - let authResponse: AuthenticationResult; - const account = this.account || (await this.getAccount()); - if (account) { - request.account = account; - authResponse = await this.getTokenSilent(request); - } else { - const authCodeRequest = { ...this.authCodeUrlParams, ...request }; - authResponse = await this.getTokenInteractive(authCodeRequest); - } - - return authResponse.accessToken || null; - } - - async getTokenSilent( - tokenRequest: SilentFlowRequest - ): Promise { - try { - return await this.clientApplication.acquireTokenSilent( - tokenRequest - ); - } catch (error) { - console.error( - "Silent token acquisition failed, acquiring token interactively" - ); - const authCodeRequest = { - ...this.authCodeUrlParams, - ...tokenRequest, - }; - return await this.getTokenInteractive(authCodeRequest); - } - } - - async getTokenInteractive( - tokenRequest: AuthorizationUrlRequest - ): Promise { - // Generate PKCE Challenge and Verifier before request - const cryptoProvider = new CryptoProvider(); - const { challenge, verifier } = - await cryptoProvider.generatePkceCodes(); - const authWindow = await AuthProvider.createAuthWindow(); - - // Add PKCE params to Auth Code URL request - const authCodeUrlParams = { - ...this.authCodeUrlParams, - scopes: tokenRequest.scopes, - codeChallenge: challenge, - codeChallengeMethod: "S256", - }; - - try { - // Get Auth Code URL - const authCodeUrl = await this.clientApplication.getAuthCodeUrl( - authCodeUrlParams - ); - - const authCode = await this.listenForAuthCode( - authCodeUrl, - authWindow - ); - - // Use Authorization Code and PKCE Code verifier to make token request - const authResult: AuthenticationResult = - await this.clientApplication.acquireTokenByCode({ - ...this.authCodeRequest, - code: authCode, - codeVerifier: verifier, - }); - - authWindow.close(); - return authResult; - } catch (error) { - authWindow.close(); - throw error; - } - } - - async login(): Promise { - const authResult = await this.getTokenInteractive( - this.authCodeUrlParams - ); - return this.handleResponse(authResult); - } - - async loginSilent(): Promise { - if (!this.account) { - this.account = await this.getAccount(); - } - - return this.account; - } - - async logout(): Promise { - if (this.account) { - await this.clientApplication - .getTokenCache() - .removeAccount(this.account); - this.account = null; - } - } - - private async listenForAuthCode( - navigateUrl: string, - authWindow: BrowserWindow - ): Promise { - // Set up custom file protocol to listen for redirect response - const authCodeListener = new CustomProtocolListener( - this.authConfig.customProtocol.name - ); - const codePromise = authCodeListener.start(); - authWindow.loadURL(navigateUrl); - const code = await codePromise; - authCodeListener.close(); - return code; - } - - /** - * Handles the response from a popup or redirect. If response is null, will check if we have any accounts and attempt to sign in. - * @param response - */ - private async handleResponse(response: AuthenticationResult) { - if (response !== null) { - this.account = response.account; - } else { - this.account = await this.getAccount(); - } - - return this.account; - } - - /** - * Calls getAllAccounts and determines the correct account to sign into, currently defaults to first account found in cache. - * TODO: Add account chooser code - * - * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-common/docs/Accounts.md - */ - private async getAccount(): Promise { - // need to call getAccount here? - const cache = this.clientApplication.getTokenCache(); - const currentAccounts = await cache.getAllAccounts(); - - if (currentAccounts === null) { - console.log("No accounts detected"); - return null; - } - - if (currentAccounts.length > 1) { - // Add choose account code here - console.log( - "Multiple accounts detected, need to add choose account code." - ); - return currentAccounts[0]; - } else if (currentAccounts.length === 1) { - return currentAccounts[0]; - } else { - return null; - } - } -} diff --git a/samples/msal-node-samples/ElectronTestApp/src/CachePlugin.ts b/samples/msal-node-samples/ElectronTestApp/src/CachePlugin.ts deleted file mode 100644 index ba57f4d89f..0000000000 --- a/samples/msal-node-samples/ElectronTestApp/src/CachePlugin.ts +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. - */ -import { ICachePlugin } from "@azure/msal-node"; -import * as fs from "fs"; - -export const cachePlugin = (CACHE_LOCATION: string): ICachePlugin => { - const beforeCacheAccess = async (cacheContext) => { - return new Promise(async (resolve, reject) => { - if (fs.existsSync(CACHE_LOCATION)) { - fs.readFile(CACHE_LOCATION, "utf-8", (error, data) => { - if (error) { - reject(); - } else { - cacheContext.tokenCache.deserialize(data); - resolve(); - } - }); - } else { - fs.writeFile( - CACHE_LOCATION, - cacheContext.tokenCache.serialize(), - (error) => { - if (error) { - reject(); - } - } - ); - } - }); - }; - - const afterCacheAccess = async (cacheContext) => { - if (cacheContext.cacheHasChanged) { - fs.writeFile( - CACHE_LOCATION, - cacheContext.tokenCache.serialize(), - (error) => { - if (error) { - console.error(error); - } - } - ); - } - }; - - return { - beforeCacheAccess, - afterCacheAccess, - }; -}; diff --git a/samples/msal-node-samples/ElectronTestApp/src/Constants.ts b/samples/msal-node-samples/ElectronTestApp/src/Constants.ts deleted file mode 100644 index ef368cacbe..0000000000 --- a/samples/msal-node-samples/ElectronTestApp/src/Constants.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. - */ - -// Add here the endpoints for MS Graph API services you would like to use. -export const GRAPH_CONFIG = { - GRAPH_ME_ENDPT: "/me", - GRAPH_MAIL_ENDPT: "/me/messages", -}; - -export enum IpcMessages { - SHOW_WELCOME_MESSAGE = "SHOW_WELCOME_MESSAGE", - LOGIN = "LOGIN", - LOGOUT = "LOGOUT", - GET_PROFILE = "GET_PROFILE", - SET_PROFILE = "SET_PROFILE", - GET_MAIL = "GET_MAIL", - SET_MAIL = "SET_MAIL", -} diff --git a/samples/msal-node-samples/ElectronTestApp/src/CustomProtocolListener.ts b/samples/msal-node-samples/ElectronTestApp/src/CustomProtocolListener.ts deleted file mode 100644 index 2e1290a2e8..0000000000 --- a/samples/msal-node-samples/ElectronTestApp/src/CustomProtocolListener.ts +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -import { AuthCodeListener } from "./AuthCodeListener"; - -import { protocol } from "electron"; - -/** - * CustomProtocolListener can be instantiated in order - * to register and unregister a custom typed protocol on which - * MSAL can listen for Auth Code reponses. - * - * For information on available protocol types, check the Electron - * protcol docs: https://www.electronjs.org/docs/latest/api/protocol/ - */ -export class CustomProtocolListener extends AuthCodeListener { - constructor(hostName: string) { - super(hostName); - } - - /** - * Registers a custom string protocol on which the library will - * listen for Auth Code response. - */ - public start(): Promise { - const codePromise = new Promise((resolve, reject) => { - protocol.registerStringProtocol(this.host, (req, callback) => { - const requestUrl = new URL(req.url); - const authCode = requestUrl.searchParams.get("code"); - - if (authCode) { - resolve(authCode); - } else { - protocol.unregisterProtocol(this.host); - reject(new Error("No code found in URL")); - } - }); - }); - - return codePromise; - } - - /** - * Unregisters a custom file protocol to stop listening for - * Auth Code response. - */ - public close() { - protocol.unregisterProtocol(this.host); - } -} diff --git a/samples/msal-node-samples/ElectronTestApp/src/FetchManager.ts b/samples/msal-node-samples/ElectronTestApp/src/FetchManager.ts deleted file mode 100644 index 0d67612474..0000000000 --- a/samples/msal-node-samples/ElectronTestApp/src/FetchManager.ts +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. - */ - -import { UserInfo, MailInfo } from "./GraphReponseTypes"; -import * as axios from "axios"; - -/** - * Class that handles Bearer requests for data using Fetch. - */ -export class FetchManager { - /** - * Makes an Authorization "Bearer" request with the given accessToken to the given endpoint. - * @param endpoint - * @param accessToken - */ - async callEndpointWithToken( - endpoint: string, - accessToken: string - ): Promise { - const options = { - headers: { - Authorization: `Bearer ${accessToken}`, - }, - }; - console.log("Request made at: " + new Date().toString()); - const response = await axios.default.get(endpoint, options); - - return (await response.data) as UserInfo | MailInfo; - } -} diff --git a/samples/msal-node-samples/ElectronTestApp/src/GraphReponseTypes.ts b/samples/msal-node-samples/ElectronTestApp/src/GraphReponseTypes.ts deleted file mode 100644 index a5c6f4506a..0000000000 --- a/samples/msal-node-samples/ElectronTestApp/src/GraphReponseTypes.ts +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. - */ - -/** - * Graph data about the user. - */ -export type UserInfo = { - businessPhones?: Array; - displayName?: string; - givenName?: string; - id?: string; - jobTitle?: string; - mail?: string; - mobilePhone?: string; - officeLocation?: string; - preferredLanguage?: string; - surname?: string; - userPrincipalName?: string; -}; - -/** - * Mail data from MS Graph - */ -export type MailInfo = { - value?: Array; -}; diff --git a/samples/msal-node-samples/ElectronTestApp/src/Main.ts b/samples/msal-node-samples/ElectronTestApp/src/Main.ts deleted file mode 100644 index e2a92b0a9e..0000000000 --- a/samples/msal-node-samples/ElectronTestApp/src/Main.ts +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. - */ - -import { app, BrowserWindow, ipcMain } from "electron"; -import * as path from "path"; - -import AuthProvider from "./AuthProvider"; -import { FetchManager } from "./FetchManager"; -import { IpcMessages, GRAPH_CONFIG } from "./Constants"; -import * as authConfig from "./config/customConfig.json"; - -export default class Main { - static application: Electron.App; - static mainWindow: Electron.BrowserWindow; - static authProvider: AuthProvider; - static fetchManager: FetchManager; - static authConfig: any; - - static main(): void { - Main.application = app; - Main.application.on("window-all-closed", Main.onWindowAllClosed); - Main.application.on("ready", Main.onReady); - - // if in automation, read the config from environment - Main.authConfig = process.env.authConfig - ? JSON.parse(process.env.authConfig) - : authConfig; - } - - private static async loadBaseUI(): Promise { - await Main.mainWindow.loadFile(path.join(__dirname, "../index.html")); - } - - private static onWindowAllClosed(): void { - // Windows and Linux will quit the application when all windows are closed - if (process.platform !== "darwin") { - // macOS requires explicit quitting - Main.application.quit(); - } - } - - private static onClose(): void { - Main.mainWindow = null; - } - - private static onReady(): void { - Main.createMainWindow(); - Main.mainWindow.loadFile(path.join(__dirname, "../index.html")); - Main.mainWindow.on("closed", Main.onClose); - Main.authProvider = new AuthProvider(Main.authConfig); - Main.fetchManager = new FetchManager(); - Main.registerSubscriptions(); - - Main.attemptSSOSilent(); - } - - // Creates main application window - private static createMainWindow(): void { - this.mainWindow = new BrowserWindow({ - width: 1000, - height: 1000, - /** - * Preload script serves as an interface between the Main process - * that has access to Node API and the Renderer process which controls - * the user interface but is otherwise not trustworthy of directly handling - * the Node API. - */ - webPreferences: { preload: path.join(__dirname, "preload.js") }, - }); - } - - private static publish(message: string, payload: any): void { - Main.mainWindow.webContents.send(message, payload); - } - - private static async attemptSSOSilent(): Promise { - const account = await Main.authProvider.loginSilent(); - await Main.loadBaseUI(); - - if (account) { - console.log("Successful silent account retrieval"); - Main.publish(IpcMessages.SHOW_WELCOME_MESSAGE, account); - } - } - - private static async login(): Promise { - const account = await Main.authProvider.login(); - await Main.loadBaseUI(); - Main.publish(IpcMessages.SHOW_WELCOME_MESSAGE, account); - } - - private static async getProfile(): Promise { - const token = await Main.authProvider.getProfileToken(); - const account = Main.authProvider.currentAccount; - await Main.loadBaseUI(); - Main.publish(IpcMessages.SHOW_WELCOME_MESSAGE, account); - const graphResponse = await Main.fetchManager.callEndpointWithToken( - `${Main.authConfig.resourceApi.endpoint}${GRAPH_CONFIG.GRAPH_ME_ENDPT}`, - token - ); - Main.publish(IpcMessages.SET_PROFILE, graphResponse); - } - - private static async getMail(): Promise { - const token = await Main.authProvider.getMailToken(); - const account = Main.authProvider.currentAccount; - await Main.loadBaseUI(); - Main.publish(IpcMessages.SHOW_WELCOME_MESSAGE, account); - const graphResponse = await Main.fetchManager.callEndpointWithToken( - `${Main.authConfig.resourceApi.endpoint}${GRAPH_CONFIG.GRAPH_ME_ENDPT}`, - token - ); - Main.publish(IpcMessages.SET_MAIL, graphResponse); - } - - private static async logout(): Promise { - await Main.authProvider.logout(); - await Main.loadBaseUI(); - } - - // Router that maps callbacks/actions to specific messages received from the Renderer - private static registerSubscriptions(): void { - ipcMain.on(IpcMessages.LOGIN, Main.login); - ipcMain.on(IpcMessages.GET_PROFILE, Main.getProfile); - ipcMain.on(IpcMessages.GET_MAIL, Main.getMail); - ipcMain.on(IpcMessages.LOGOUT, Main.logout); - } -} diff --git a/samples/msal-node-samples/ElectronTestApp/src/Renderer.ts b/samples/msal-node-samples/ElectronTestApp/src/Renderer.ts deleted file mode 100644 index 8ae69c5546..0000000000 --- a/samples/msal-node-samples/ElectronTestApp/src/Renderer.ts +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License - -/** - * The renderer API is exposed by the preload script found in the preload.ts - * file in order to give the renderer access to the Node API in a secure and - * controlled way - */ -// @ts-ignore -const renderer = window.renderer; -// @ts-ignore -window.renderer.startUiManager(); - -// UI event handlers -document.querySelector("#SignIn").addEventListener("click", () => { - renderer.sendLoginMessage(); -}); - -document.querySelector("#SignOut").addEventListener("click", () => { - renderer.sendSignoutMessage(); -}); - -document.querySelector("#seeProfile").addEventListener("click", () => { - renderer.sendSeeProfileMessage(); -}); - -document.querySelector("#readMail").addEventListener("click", () => { - renderer.sendReadMailMessage(); -}); diff --git a/samples/msal-node-samples/ElectronTestApp/src/UIManager.ts b/samples/msal-node-samples/ElectronTestApp/src/UIManager.ts deleted file mode 100644 index e58b8b57aa..0000000000 --- a/samples/msal-node-samples/ElectronTestApp/src/UIManager.ts +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. - */ - -import { AccountInfo } from "@azure/msal-node"; -import { UserInfo, MailInfo } from "./GraphReponseTypes"; -import { GRAPH_CONFIG } from "./Constants"; - -/** - * Class that handles UI updates for the app. - */ -export class UIManager { - // Select DOM elements to work with - private welcomeDiv: HTMLElement; - private signInButton: HTMLElement; - private signOutButton: HTMLElement; - private cardDiv: HTMLElement; - private mailButton: HTMLElement; - private profileButton: HTMLElement; - private profileDiv: HTMLElement; - private tabList: HTMLElement; - private tabContent: HTMLElement; - - constructor() { - this.welcomeDiv = document.getElementById("WelcomeMessage"); - this.signInButton = document.getElementById("SignIn"); - this.signOutButton = document.getElementById("SignOut"); - this.cardDiv = document.getElementById("card-div"); - this.mailButton = document.getElementById("readMail"); - this.profileButton = document.getElementById("seeProfile"); - this.profileDiv = document.getElementById("profile-div"); - this.tabList = document.getElementById("list-tab"); - this.tabContent = document.getElementById("nav-tabContent"); - } - - public showWelcomeMessage(account: AccountInfo) { - // Reconfiguring DOM elements - this.cardDiv.style.display = "initial"; - this.welcomeDiv.innerHTML = `Welcome ${account.username}`; - this.signInButton.hidden = true; - this.signOutButton.hidden = false; - } - - public clearTabs() { - this.tabList.innerHTML = ""; - this.tabContent.innerHTML = ""; - } - - public updateUI(data: UserInfo | MailInfo, endpoint: string) { - console.log(`Graph API responded at: ${new Date().toString()}`); - if (endpoint === GRAPH_CONFIG.GRAPH_ME_ENDPT) { - this.setProfile(data as UserInfo); - } else if (endpoint === GRAPH_CONFIG.GRAPH_MAIL_ENDPT) { - this.setMail(data as MailInfo); - } - } - - public setProfile(data: UserInfo) { - const userInfo = data as UserInfo; - const profile = document.createElement("pre"); - profile.innerHTML = JSON.stringify(userInfo, null, 4); - this.clearTabs(); - this.tabContent.appendChild(profile); - } - - public setMail(data: MailInfo) { - const mailInfo = data as MailInfo; - if (mailInfo.value.length < 1) { - alert("Your mailbox is empty!"); - } else { - this.clearTabs(); - mailInfo.value.slice(0, 10).forEach((d: any, i) => { - this.createAndAppendListItem(d, i); - this.createAndAppendContentItem(d, i); - }); - } - } - - public createAndAppendListItem(d: any, i: Number) { - const listItem = document.createElement("a"); - listItem.setAttribute( - "class", - "list-group-item list-group-item-action" - ); - listItem.setAttribute("id", "list" + i + "list"); - listItem.setAttribute("data-toggle", "list"); - listItem.setAttribute("href", "#list" + i); - listItem.setAttribute("role", "tab"); - listItem.setAttribute("aria-controls", `${i}`); - listItem.innerHTML = d.subject; - this.tabList.appendChild(listItem); - } - - public createAndAppendContentItem(d: any, i: Number) { - const contentItem = document.createElement("div"); - contentItem.setAttribute("class", "tab-pane fade"); - contentItem.setAttribute("id", "list" + i); - contentItem.setAttribute("role", "tabpanel"); - contentItem.setAttribute("aria-labelledby", "list" + i + "list"); - if (d.from) { - contentItem.innerHTML = - " from: " + - d.from.emailAddress.address + - "

" + - d.bodyPreview + - "..."; - this.tabContent.appendChild(contentItem); - } - } -} diff --git a/samples/msal-node-samples/ElectronTestApp/src/config/AAD.json b/samples/msal-node-samples/ElectronTestApp/src/config/AAD.json deleted file mode 100644 index 9127c16bf9..0000000000 --- a/samples/msal-node-samples/ElectronTestApp/src/config/AAD.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "authOptions": { - "clientId": "4b0db8c2-9f26-4417-8bde-3f0e3656f8e0", - "authority": "https://login.microsoftonline.com/common/" - }, - "request": { - "authCodeUrlParameters": { - "scopes": ["user.read"], - "redirectUri": "msal4b0db8c2-9f26-4417-8bde-3f0e3656f8e0://auth" - }, - "authCodeRequest": { - "scopes": ["User.Read"], - "redirectUri": "msal4b0db8c2-9f26-4417-8bde-3f0e3656f8e0://auth" - } - }, - "resourceApi": { - "endpoint": "https://graph.microsoft.com/v1.0/me" - }, - "customProtocol": { - "name": "msal4b0db8c2-9f26-4417-8bde-3f0e3656f8e0" - }, - "cache": { - "cacheLocation": "./data/aad.cache.json" - } -} diff --git a/samples/msal-node-samples/ElectronTestApp/src/config/ADFS.json b/samples/msal-node-samples/ElectronTestApp/src/config/ADFS.json deleted file mode 100644 index 4c81a21130..0000000000 --- a/samples/msal-node-samples/ElectronTestApp/src/config/ADFS.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "authOptions": { - "clientId": "c3f3b506-8ca9-4c23-acda-035ee2c9d960", - "authority": "https://login.microsoftonline.com/common" - }, - "request": { - "authCodeUrlParameters": { - "scopes": ["user.read"], - "redirectUri": "msal4b0db8c2-9f26-4417-8bde-3f0e3656f8e0://auth" - }, - "authCodeRequest": { - "scopes": ["user.read"], - "redirectUri": "msal4b0db8c2-9f26-4417-8bde-3f0e3656f8e0://auth" - } - }, - "resourceApi": { - "endpoint": "https://graph.microsoft.com/v1.0/me" - }, - "customProtocol": { - "name": "msal4b0db8c2-9f26-4417-8bde-3f0e3656f8e0" - }, - "cache": { - "cacheLocation": "./data/adfs.cache.json" - } -} diff --git a/samples/msal-node-samples/ElectronTestApp/src/config/customConfig.json b/samples/msal-node-samples/ElectronTestApp/src/config/customConfig.json deleted file mode 100644 index b200661f66..0000000000 --- a/samples/msal-node-samples/ElectronTestApp/src/config/customConfig.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "authOptions": - { - "clientId": "8fcb9fc1-d8f9-49c0-b80e-a8a8a201d051", - "authority": "https://login.windows-ppe.net/common/" - }, - "request": - { - "authCodeUrlParameters": { - "scopes": ["user.read"], - "redirectUri": "msal4b0db8c2-9f26-4417-8bde-3f0e3656f8e0://auth" - }, - "authCodeRequest": { - "redirectUri": "msal4b0db8c2-9f26-4417-8bde-3f0e3656f8e0://auth", - "scopes": ["User.Read"] - } - }, - "resourceApi": - { - "endpoint": "https://graph.microsoft-ppe.com/v1.0/me" - }, - "customProtocol": - { - "name": "msal4b0db8c2-9f26-4417-8bde-3f0e3656f8e0" - }, - "cache": { - "cacheLocation": "./data/cache.json" - } -} diff --git a/samples/msal-node-samples/ElectronTestApp/src/preload.ts b/samples/msal-node-samples/ElectronTestApp/src/preload.ts deleted file mode 100644 index 66a05ef1b7..0000000000 --- a/samples/msal-node-samples/ElectronTestApp/src/preload.ts +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License - -import { contextBridge, ipcRenderer } from "electron"; -import { UIManager } from "./UIManager"; - -import { GRAPH_CONFIG, IpcMessages } from "./Constants"; - -/** - * This preload script exposes a "renderer" API to give - * the Renderer process controlled access to some Node APIs - * by leveraging IPC channels that have been configured for - * communication between the Main and Renderer processes. - */ -contextBridge.exposeInMainWorld("renderer", { - sendLoginMessage: () => { - ipcRenderer.send(IpcMessages.LOGIN); - }, - sendSignoutMessage: () => { - ipcRenderer.send(IpcMessages.LOGOUT); - }, - sendSeeProfileMessage: () => { - ipcRenderer.send(IpcMessages.GET_PROFILE); - }, - sendReadMailMessage: () => { - ipcRenderer.send(IpcMessages.GET_MAIL); - }, - /** - * This method will be called by the Renderer - * to give the preload script access to the UI manager - */ - startUiManager: () => { - /** - * The UI Manager is declared within this API because - * although it's used in the listeners below, it must be initialized by the Renderer - * process in order for the DOM to be accessible through JavaScript. - */ - const uiManager = new UIManager(); - - // Main process message subscribers - ipcRenderer.on(IpcMessages.SHOW_WELCOME_MESSAGE, (event, account) => { - uiManager.showWelcomeMessage(account); - }); - - ipcRenderer.on(IpcMessages.SET_PROFILE, (event, graphResponse) => { - uiManager.updateUI(graphResponse, GRAPH_CONFIG.GRAPH_ME_ENDPT); - }); - - ipcRenderer.on(IpcMessages.SET_MAIL, (event, graphResponse) => { - uiManager.updateUI(graphResponse, GRAPH_CONFIG.GRAPH_MAIL_ENDPT); - }); - }, -}); diff --git a/samples/msal-node-samples/ElectronTestApp/tsconfig.json b/samples/msal-node-samples/ElectronTestApp/tsconfig.json deleted file mode 100644 index c4499bf236..0000000000 --- a/samples/msal-node-samples/ElectronTestApp/tsconfig.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "compilerOptions": { - "moduleResolution": "node", - "module": "commonjs", - "target": "es5", - "resolveJsonModule": true, - "sourceMap": true, - "removeComments": false, - "outDir": "dist", - "noImplicitReturns": true, - "types": [] - }, - "include": [ - "./src/**/*" - ], - "exclude": [ - "node_modules" - ] -} \ No newline at end of file diff --git a/samples/msal-node-samples/auth-code-pkce/.npmrc b/samples/msal-node-samples/auth-code-pkce/.npmrc deleted file mode 100644 index 43c97e719a..0000000000 --- a/samples/msal-node-samples/auth-code-pkce/.npmrc +++ /dev/null @@ -1 +0,0 @@ -package-lock=false diff --git a/samples/msal-node-samples/auth-code-pkce/README.md b/samples/msal-node-samples/auth-code-pkce/README.md deleted file mode 100644 index 8d7cc92751..0000000000 --- a/samples/msal-node-samples/auth-code-pkce/README.md +++ /dev/null @@ -1,51 +0,0 @@ -# MSAL Node Standalone Sample: Authorization Code Grant (PKCE) In Typescript - -This sample demonstrates an MSAL Node [public client application](../../../lib/msal-node/docs/initialize-public-client-application.md) that lets users authenticate against **Microsoft Entra ID**. - -This sample uses the [OAuth 2.0 Authorization Code Grant](https://oauth.net/2/grant-types/authorization-code/) flow with [Proof-Key For Code Exchange](https://oauth.net/2/pkce/) (PKCE). This flow is particularly suitable for public client applications like desktop and mobile apps. - -> This sample demonstrates how to use and setup `msal-node` in a [typescript](https://www.typescriptlang.org) project. - -## Setup - -Locate the folder where `package.json` resides in your terminal. Then type: - -```console - npm install -``` - -## Register - -1. Navigate to the [Microsoft Entra admin center](https://entra.microsoft.com) and select the **Microsoft Entra ID** service. -1. Select the **App Registrations** blade on the left, then select **New registration**. -1. In the **Register an application page** that appears, enter your application's registration information: - - In the **Name** section, enter a meaningful application name that will be displayed to users of the app, for example `msal-node-webapp`. - - Under **Supported account types**, select **Accounts in this organizational directory only**. - - In the **Redirect URI (optional)** section, select **Public client/native (mobile & desktop)** in the combo-box and enter the following redirect URI: `http://localhost:3000/redirect`. -1. Select **Register** to create the application. -1. In the app's registration screen, find and note the **Application (client) ID** and **Directory (Tenant) ID**. You use these values in your app's configuration file(s) later. - -Before running the sample, you will need to replace the values in the configuration object: - -```javascript -const config = { - auth: { - clientId: "ENTER_CLIENT_ID", - authority: "https://login.microsoftonline.com/ENTER_TENANT_ID", - }, -}; -``` - -## Run the app - -In the same folder, type: - -```console - npm start -``` - -The server should start at port **3000**. Navigate to `http://localhost:3000` in your browser, which will trigger the token acquisition process. - -## More information - -- [Microsoft identity platform OAuth 2.0 Authorization Code Grant](https://docs.microsoft.com/azure/active-directory/develop/v2-oauth2-auth-code-flow) diff --git a/samples/msal-node-samples/auth-code-pkce/package.json b/samples/msal-node-samples/auth-code-pkce/package.json deleted file mode 100644 index 1b8a6cb03d..0000000000 --- a/samples/msal-node-samples/auth-code-pkce/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "msal-node-auth-code-pkce", - "version": "1.0.0", - "description": "sample for msal-node public client application using using auth code flow with PKCE to sign-in users on azure ad", - "main": "dist/index.js", - "private": true, - "scripts": { - "build": "tsc", - "build:package": "cd ../../../lib/msal-common && npm run build && cd ../msal-node && npm run build", - "prestart": "npm run build", - "start": "node .", - "start:build": "npm run build:package && npm start" - }, - "author": "Microsoft", - "license": "MIT", - "dependencies": { - "@azure/msal-node": "^3.0.0", - "dotenv": "^16.5.0", - "express": "^4.20.0", - "express-session": "^1.17.2" - }, - "devDependencies": { - "@types/express": "^4.17.13", - "@types/express-session": "^1.17.4", - "@types/node": "^16.10.1", - "typescript": "^4.4.3" - } -} diff --git a/samples/msal-node-samples/auth-code-pkce/src/index.ts b/samples/msal-node-samples/auth-code-pkce/src/index.ts deleted file mode 100644 index 2a1ef22a5f..0000000000 --- a/samples/msal-node-samples/auth-code-pkce/src/index.ts +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. - */ -import express from "express"; -import session from "express-session"; -import { - PublicClientApplication, - AuthorizationCodeRequest, - LogLevel, - CryptoProvider, - AuthorizationUrlRequest, - Configuration, -} from "@azure/msal-node"; -import { RequestWithPKCE } from "./types"; -import "dotenv/config"; - -const SERVER_PORT = process.env.PORT || 3000; - -// Before running the sample, you will need to replace the values in the config. -const config: Configuration = { - auth: { - clientId: "ENTER_CLIENT_ID", - authority: "https://login.microsoftonline.com/ENTER_TENANT_ID", - }, - system: { - loggerOptions: { - loggerCallback( - loglevel: LogLevel, - message: string, - containsPii: boolean - ) { - console.log(message); - }, - piiLoggingEnabled: false, - logLevel: LogLevel.Verbose, - }, - }, -}; - -// Create msal application object -const pca = new PublicClientApplication(config); - -// Create Express App and Routes -const app = express(); - -/** - * Using express-session middleware. Be sure to familiarize yourself with available options - * and set them as desired. Visit: https://www.npmjs.com/package/express-session - */ -const sessionConfig = { - secret: process.env.SECRET, - resave: false, - saveUninitialized: false, - cookie: { - secure: false, // set this to true on production - }, -}; - -if (app.get("env") === "production") { - app.set("trust proxy", 1); // trust first proxy e.g. App Service - sessionConfig.cookie.secure = true; // serve secure cookies -} - -app.use(session(sessionConfig)); - -app.get("/", (req: RequestWithPKCE, res) => { - /** - * Proof Key for Code Exchange (PKCE) Setup - * - * MSAL enables PKCE in the Authorization Code Grant Flow by including the codeChallenge and codeChallengeMethod parameters - * in the request passed into getAuthCodeUrl() API, as well as the codeVerifier parameter in the - * second leg (acquireTokenByCode() API). - * - * MSAL Node provides PKCE Generation tools through the CryptoProvider class, which exposes - * the generatePkceCodes() asynchronous API. As illustrated in the example below, the verifier - * and challenge values should be generated previous to the authorization flow initiation. - * - * For details on PKCE code generation logic, consult the - * PKCE specification https://tools.ietf.org/html/rfc7636#section-4 - */ - - // Initialize CryptoProvider instance - const cryptoProvider = new CryptoProvider(); - // Generate PKCE Codes before starting the authorization flow - cryptoProvider.generatePkceCodes().then(({ verifier, challenge }) => { - // create session object if does not exist - if (!req.session.pkceCodes) { - req.session.pkceCodes = { - challengeMethod: "S256", - }; - } - - // Set generated PKCE Codes as session vars - req.session.pkceCodes.verifier = verifier; - req.session.pkceCodes.challenge = challenge; - - // Add PKCE code challenge and challenge method to authCodeUrl request objectgit st - const authCodeUrlParameters: AuthorizationUrlRequest = { - scopes: ["user.read"], - redirectUri: "http://localhost:3000/redirect", - codeChallenge: req.session.pkceCodes.challenge, // PKCE Code Challenge - codeChallengeMethod: req.session.pkceCodes.challengeMethod, // PKCE Code Challenge Method - }; - - // Get url to sign user in and consent to scopes needed for applicatio - pca.getAuthCodeUrl(authCodeUrlParameters).then((response) => { - res.redirect(response); - }); - }); -}); - -app.get("/redirect", (req: RequestWithPKCE, res) => { - // Add PKCE code verifier to token request object - const tokenRequest: AuthorizationCodeRequest = { - code: req.query.code as string, - scopes: ["user.read"], - redirectUri: "http://localhost:3000/redirect", - codeVerifier: req.session.pkceCodes.verifier, // PKCE Code Verifier - clientInfo: req.query.client_info as string, - }; - - pca.acquireTokenByCode(tokenRequest) - .then(() => { - res.sendStatus(200); - }) - .catch((error) => { - res.status(500).send(error.errorMessage); - }); -}); - -app.listen(SERVER_PORT, () => - console.log( - `Msal Node Auth Code Sample app listening on port ${SERVER_PORT}!` - ) -); diff --git a/samples/msal-node-samples/auth-code-pkce/src/types/index.ts b/samples/msal-node-samples/auth-code-pkce/src/types/index.ts deleted file mode 100644 index 6ca1bad83c..0000000000 --- a/samples/msal-node-samples/auth-code-pkce/src/types/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Request } from "express"; -import { Session } from "express-session"; - -export type RequestWithPKCE = Request & { - session: Session & { - pkceCodes: { - challengeMethod: string; - challenge?: string; - verifier?: string; - }; - }; -}; diff --git a/samples/msal-node-samples/auth-code-pkce/tsconfig.json b/samples/msal-node-samples/auth-code-pkce/tsconfig.json deleted file mode 100644 index 66829f17ed..0000000000 --- a/samples/msal-node-samples/auth-code-pkce/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "compilerOptions": { - "module": "commonjs", - "esModuleInterop": true, - "target": "es6", - "noImplicitAny": true, - "moduleResolution": "node", - "sourceMap": true, - "outDir": "dist", - "baseUrl": ".", - "paths": { - "*": ["node_modules/*"] - } - }, - "include": ["src/**/*"] -} \ No newline at end of file diff --git a/samples/msal-node-samples/refresh-token/.npmrc b/samples/msal-node-samples/refresh-token/.npmrc deleted file mode 100644 index 43c97e719a..0000000000 --- a/samples/msal-node-samples/refresh-token/.npmrc +++ /dev/null @@ -1 +0,0 @@ -package-lock=false diff --git a/samples/msal-node-samples/refresh-token/README.md b/samples/msal-node-samples/refresh-token/README.md deleted file mode 100644 index 3c1ca9a5b2..0000000000 --- a/samples/msal-node-samples/refresh-token/README.md +++ /dev/null @@ -1,150 +0,0 @@ -# MSAL Node Standalone Sample: Refresh Token Grant - -This sample demonstrates how to implement an MSAL Node [confidential client application](../../../lib/msal-node/docs/initialize-confidential-client-application.md) to exchange a refresh token for an access token when the said access token has expired, using the [OAuth 2.0 Refresh Token](https://oauth.net/2/grant-types/refresh-token/) grant. - -Note that MSAL does not expose refresh tokens by default and developers are not expected to build logic around them, as MSAL handles the token refreshing process itself. However, the `acquireTokenByRefreshToken` API is useful in certain cases: for instance, if you are storing refresh tokens in a separate location (e.g. in an encrypted cache file) and you would like to use it to renew an access token or if you're migrating from ADAL Node to MSAL Node and you would like to make use of your previously acquired (and still valid) refresh tokens. With respect to the latter, this sample also demonstrates one possible strategy for migration below. - -> :warning: Confidential client applications should not share cache and we do not recommend cache sharing between an ADAL app and an MSAL app. msal-node will not be able to directly read from an ADAL app's cache. Make sure to isolate cache locations and provide only the relevant refresh token string to msal-node's `acquireTokenByRefreshToken` API. - -## Setup - -Locate the folder where `package.json` resides in your terminal. Then type: - -```console - npm install -``` - -## Register - -1. Navigate to the [Microsoft Entra admin center](https://entra.microsoft.com) and select the **Microsoft Entra ID** service. -1. Select the **App Registrations** blade on the left, then select **New registration**. -1. In the **Register an application page** that appears, enter your application's registration information: - - In the **Name** section, enter a meaningful application name that will be displayed to users of the app, for example `msal-node-app`. - - Under **Supported account types**, select **Accounts in this organizational directory only**. - - In the **Redirect URI (optional)** section, select **Web** in the combo-box and enter the following redirect URI: `http://localhost:3000/redirect`. -1. Select **Register** to create the application. -1. In the app's registration screen, find and note the **Application (client) ID** and **Directory (Tenant) ID**. You use these values in your app's configuration file(s) later. -1. In the app's registration screen, select the **Certificates & secrets** blade in the left. - - In the **Client secrets** section, select **New client secret**. - - Type a key description (for instance `app secret`), - - Select one of the available key durations (6 months, 12 months or Custom) as per your security posture. - - The generated key value will be displayed when you select the **Add** button. Copy and add this client secret to the `.env` file as `CLIENT_SECRET`. - -Before running the sample, you will need to replace the values in the [customConfig.json](./config/customConfig.json): - -**customConfig.json** - -```JSON -{ - "tenantInfo:": "ENTER_TENANT_INFO", - "clientId": "ENTER_CLIENT_ID", -} -``` - -**.env file** - -``` -CLIENT_SECRET= -``` - -## Test the app - -1. First, run the ADAL Node application. In your terminal, type: - -```console - npm run start:adal -``` - -1. Open a browser and navigate to `http://localhost:3000`. The app will attempt to interactively acquire tokens for the user. Enter your credentials and consent to the permissions required by the app. Once you do, you should be redirected back to the app, and see the token acquisition response printed on the page. At this point, your tokens should be cached in a file named [cache.json](./data/cache.json) under the _data_ folder. -1. Stop the ADAL Node app in your terminal. -1. Now start the MSAL Node app. In your terminal, type: - -```console - npm run start:msal -``` - -1. Open a browser and navigate to `http://localhost:3000`. The app will attempt to silently acquire tokens for the user. Should the silent token acquisition attempt fails, it will try to obtain a refresh token from ADAL Node app's cache. To do this, the app needs to pass down some unique identifier (such as a username or user OID) for this user as a query for the cache lookup. If no refresh token is found for this user or if the refresh token is expired, the app falls back to interactive token acquisition as a last resort. This logic is shown below: - -```JavaScript -app.get('/acquireToken', async (req, res, next) => { - try { - // retrieve account - const account = await (await cca.getTokenCache()).getAccountByHomeId(req.session.account?.homeAccountId); - - if (!account) { - console.log('Account not found!'); - throw new msal.InteractionRequiredAuthError(); - } - - const tokenResponse = await cca.acquireTokenSilent({ - account: account, - scopes: ["user.read"], - }); - - res.send(tokenResponse); - } catch (error) { - if (error instanceof msal.InteractionRequiredAuthError) { - /** - * If the silent token acquisition throws an interaction_required error, - * we catch it and attempt to find a refresh token for this user from ADAL cache. - * If no cached refresh token is found or if the refresh token is expired, - * we fallback to interactive flow via getAuthCodeUrl -> acquireTokenByCode. - */ - diskCache.find({ userId: req.cookies.userId }, async (error, data) => { - try { - if (error || !data || !data.length) throw new Error('Could not retrieve user cache'); - - /** - * You can add the /.default scope suffix to the resource to help migrate your apps - * from the v1.0 endpoint (ADAL) to the Microsoft identity platform (MSAL). - * For example, for the resource value of https://graph.microsoft.com, - * the equivalent scope value is https://graph.microsoft.com/.default - */ - const tokenResponse = await cca.acquireTokenByRefreshToken({ - refreshToken: data[0].refreshToken, - scopes: ['https://graph.microsoft.com/.default'], - forceCache: true, - }); - - req.session.account = tokenResponse.account; - - /** - * Once you successfully acquire an access token using a refresh token, - * we recommend to clear the ADAL cache for this user. - */ - diskCache.remove(data, (error, data) => { - if (error) console.error(error) - res.send(tokenResponse); - }) - } catch (error) { - // create a random string of characters against csrf - req.session.state = cryptoProvider.createNewGuid(); - - // Construct a request object for auth code url - const authCodeUrlParameters = { - scopes: ["user.read"], - responseMode: 'form_post', - redirectUri: REDIRECT_URI, - state: req.session.state, - }; - - try { - // Request auth code url, then redirect - const authCodeUrl = await cca.getAuthCodeUrl(authCodeUrlParameters); - res.redirect(authCodeUrl); - } catch (error) { - next(error); - } - } - }); - } else { - next(error); - } - } -}); -``` - -## More information - -- [Microsoft identity platform refresh tokens](https://docs.microsoft.com/azure/active-directory/develop/refresh-tokens) -- [How to migrate a Node.js app from ADAL to MSAL](https://docs.microsoft.com/azure/active-directory/develop/msal-node-migration) diff --git a/samples/msal-node-samples/refresh-token/adalApp.js b/samples/msal-node-samples/refresh-token/adalApp.js deleted file mode 100644 index b931e9d838..0000000000 --- a/samples/msal-node-samples/refresh-token/adalApp.js +++ /dev/null @@ -1,99 +0,0 @@ -// Import dependencies -var express = require('express'); -var session = require('express-session'); -var crypto = require('crypto'); -var adal = require('adal-node'); - -var config = require('./config/customConfig.json'); - -var DiskCache = require('./adalCustomCache'); -var diskCache = new DiskCache(config.adalCacheLocation); - -// Authentication parameters -var clientId = config.clientId; -var clientSecret = config.clientSecret; -var tenant = config.tenantInfo; -var authorityUrl = config.authority + '/' + tenant; -var redirectUri = config.redirectUri; -var resource = config.resource; - -// Configure logging -adal.Logging.setLoggingOptions({ - log: function (level, message, error) { - console.log(message); - }, - level: adal.Logging.LOGGING_LEVEL.VERBOSE, - loggingWithPII: false -}); - -// Auth code request URL template -var templateAuthzUrl = authorityUrl + '/oauth2/authorize?response_type=code&client_id=' - + clientId + '&redirect_uri=' + redirectUri - + '&state=&resource=' + resource; - -// Initialize express -var app = express(); - -/** - * Using express-session middleware for persistent user session. Be sure to - * familiarize yourself with available options. Visit: https://www.npmjs.com/package/express-session - */ -app.use(session({ - secret: clientSecret, - resave: false, - saveUninitialized: false, - cookie: { - secure: false, // set this to true on production - } -})); - -app.get('/', function (req, res) { - - // Create a random string to use against XSRF - crypto.randomBytes(48, function (ex, buf) { - req.session.state = buf.toString('base64') - .replace(/\//g, '_') - .replace(/\+/g, '-'); - - // Construct auth code request URL - var authorizationUrl = templateAuthzUrl - .replace('', req.session.state); - - res.redirect(authorizationUrl); - }); -}); - -app.get('/redirect', function (req, res, next) { - // Compare state parameter against XSRF - if (req.session.state !== req.query.state) { - res.send('error: state does not match'); - } - - // Initialize an AuthenticationContext object - var authenticationContext = new adal.AuthenticationContext(authorityUrl, true, diskCache); - - // Exchange auth code for tokens - authenticationContext.acquireTokenWithAuthorizationCode( - req.query.code, - redirectUri, - resource, - clientId, - clientSecret, - function (error, response) { - if (error) return next(error); - - // cache the response - authenticationContext.cache.add([response], function (error, result) { - if (error) return next(error); - console.log(result); - }); - - // create a cookie and store the userId (oid), which will be picked up later on by the MSAL app - res.cookie('userId', response.userId, { maxAge: 900000, httpOnly: true }).send(response); - } - ); -}); - -app.listen(3000, function () { - console.log('listening on port 3000!'); -}); diff --git a/samples/msal-node-samples/refresh-token/adalCustomCache.js b/samples/msal-node-samples/refresh-token/adalCustomCache.js deleted file mode 100644 index 13a9919a02..0000000000 --- a/samples/msal-node-samples/refresh-token/adalCustomCache.js +++ /dev/null @@ -1,114 +0,0 @@ -var fs = require('fs'); -var _ = require('underscore'); - -/** - * Constructs a new token cache on disk. - * This effectively implements the ADAL TokenCache interface. - * @constructor - */ -function DiskCache(cacheLocation) { - this._cacheLocation = cacheLocation; - this._entries = []; -} - -/** - * Removes a collection of entries from the cache in a single batch operation. - * @param {Array} entries An array of cache entries to remove. - * @param {Function} callback This function is called when the operation is complete. Any error is provided as the first parameter. - */ -DiskCache.prototype.remove = function (entries, callback) { - var cachedEntries = _readCache.call(this); - - var updatedEntries = _.filter(cachedEntries, function (element) { - if (_.findWhere(entries, element)) { - return false; - } - return true; - }); - - _writeCache.call(this, updatedEntries); - callback(); -}; - -/** - * Adds a collection of entries to the cache in a single batch operation. - * @param {Array} entries An array of entries to add to the cache. - * @param {Function} callback This function is called when the operation is complete. Any error is provided as the first parameter. - */ -DiskCache.prototype.add = function (entries, callback) { - var cachedEntries = _readCache.call(this); - - // Remove any entries that are duplicates of the existing - // cache elements. - _.each(cachedEntries, function (element) { - _.each(entries, function (addElement, index) { - if (entriesHaveEqualHashKeys(element, addElement)) { - entries[index] = null; - } - }); - }); - - // Add the new entries to the end of the cache. - var newEntries = _.compact(entries); - - for (var i = 0; i < newEntries.length; i++) { - cachedEntries.push(newEntries[i]); - } - - _writeCache.call(this, cachedEntries); - callback(null, true); -}; - -/** - * Finds all entries in the cache that match all of the passed in values. - * @param {object} query This object will be compared to each entry in the cache. - * Any entries that match all of the values in this object will be returned. All the values - * in the passed in object must match values in a potentially returned object - * exactly. The returned object may have more values than the passed in query object. - * @param {Function} callback - */ -DiskCache.prototype.find = function (query, callback) { - var cachedEntries = _readCache.call(this); - var results = _.where(cachedEntries, query); - callback(null, results); -}; - -function _readCache() { - if (fs.existsSync(this._cacheLocation)) { - var data = fs.readFileSync(this._cacheLocation); - this._entries = JSON.parse(data); - } else { - fs.writeFile(this._cacheLocation, JSON.stringify(this._entries), (error) => { - if (error) { - throw error; - } - }); - } - - return this._entries; -} - -function _writeCache(data) { - fs.writeFile(this._cacheLocation, JSON.stringify(data), (error) => { - if (error) { - throw error; - } - }); -} - -function entriesHaveEqualHashKeys(a, b) { - return _.isEqual(extractCacheKeyFromEntry(a), extractCacheKeyFromEntry(b)); -} - -function extractCacheKeyFromEntry(entry) { - if (!entry) return null; - - return { - _clientId: entry._clientId, - _authority: entry._authority, - userId: entry.userId, - resource: entry.resource - }; -} - -module.exports = DiskCache diff --git a/samples/msal-node-samples/refresh-token/config/customConfig.json b/samples/msal-node-samples/refresh-token/config/customConfig.json deleted file mode 100644 index bd3b895427..0000000000 --- a/samples/msal-node-samples/refresh-token/config/customConfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "tenantInfo": "ENTER_TENANT_INFO", - "clientId": "ENTER_CLIENT_ID", - "authority": "https://login.microsoftonline.com", - "redirectUri": "http://localhost:3000/redirect", - "adalCacheLocation": "./data/adal.cache.json", - "msalCacheLocation": "./data/msal.cache.json", - "resource": "https://graph.microsoft.com" -} \ No newline at end of file diff --git a/samples/msal-node-samples/refresh-token/data/adal.cacheTemplate.json b/samples/msal-node-samples/refresh-token/data/adal.cacheTemplate.json deleted file mode 100644 index 5211054944..0000000000 --- a/samples/msal-node-samples/refresh-token/data/adal.cacheTemplate.json +++ /dev/null @@ -1,16 +0,0 @@ -[ - { - "tokenType": "Bearer", - "expiresIn": 4987, - "expiresOn": "2022-06-29T18:57:39.648Z", - "resource": "https://graph.microsoft.com", - "accessToken": "eyJ0...", - "refreshToken": "0.AUU...", - "userId": "janedoe@mytenant.onmicrosoft.com", - "isUserIdDisplayable": true, - "familyName": "Doe", - "givenName": "Jane", - "oid": "91b9b524-e4d0-4133-aafd-1ff32e3e7cfc", - "tenantId": "a541e3eb-8333-48a0-a635-2a08f6726ece" - } -] diff --git a/samples/msal-node-samples/refresh-token/data/msal.cacheTemplate.json b/samples/msal-node-samples/refresh-token/data/msal.cacheTemplate.json deleted file mode 100644 index d3fdd20f5b..0000000000 --- a/samples/msal-node-samples/refresh-token/data/msal.cacheTemplate.json +++ /dev/null @@ -1,73 +0,0 @@ -{ - "Account": { - "uid.utid-login.microsoftonline.com-microsoft": { - "username": "John Doe", - "local_account_id": "object1234", - "realm": "microsoft", - "environment": "login.microsoftonline.com", - "home_account_id": "uid.utid", - "authority_type": "MSSTS", - "client_info": "base64encodedjson" - } - }, - "RefreshToken": { - "uid.utid-login.microsoftonline.com-refreshtoken-mock_client_id--": { - "environment": "login.microsoftonline.com", - "credential_type": "RefreshToken", - "secret": "a refresh token", - "client_id": "mock_client_id", - "home_account_id": "uid.utid" - }, - "uid.utid-login.microsoftonline.com-refreshtoken-1--": { - "environment": "login.microsoftonline.com", - "credential_type": "RefreshToken", - "secret": "a refresh token", - "client_id": "mock_client_id", - "home_account_id": "uid.utid", - "familyId": "1" - } - }, - "AccessToken": { - "uid.utid-login.microsoftonline.com-accesstoken-mock_client_id-microsoft-scope1 scope2 scope3": { - "environment": "login.microsoftonline.com", - "credential_type": "AccessToken", - "secret": "an access token", - "realm": "microsoft", - "target": "scope1 scope2 scope3", - "client_id": "mock_client_id", - "cached_at": "1000", - "home_account_id": "uid.utid", - "extended_expires_on": "4600", - "expires_on": "4600" - }, - "uid.utid-login.microsoftonline.com-accesstoken-mock_client_id-microsoft-scope4 scope5": { - "environment": "login.microsoftonline.com", - "credential_type": "AccessToken", - "secret": "an access token", - "realm": "microsoft", - "target": "scope4 scope5", - "client_id": "mock_client_id", - "cached_at": "1000", - "home_account_id": "uid.utid", - "extended_expires_on": "4600", - "expires_on": "4600" - } - }, - "IdToken": { - "uid.utid-login.microsoftonline.com-idtoken-mock_client_id-microsoft-": { - "realm": "microsoft", - "environment": "login.microsoftonline.com", - "credential_type": "IdToken", - "secret": "header.eyJvaWQiOiAib2JqZWN0MTIzNCIsICJwcmVmZXJyZWRfdXNlcm5hbWUiOiAiSm9obiBEb2UiLCAic3ViIjogInN1YiJ9.signature", - "client_id": "mock_client_id", - "home_account_id": "uid.utid" - } - }, - "AppMetadata": { - "appmetadata-login.microsoftonline.com-mock_client_id": { - "environment": "login.microsoftonline.com", - "family_id": "1", - "client_id": "mock_client_id" - } - } -} diff --git a/samples/msal-node-samples/refresh-token/msalApp.js b/samples/msal-node-samples/refresh-token/msalApp.js deleted file mode 100644 index b3700c2d80..0000000000 --- a/samples/msal-node-samples/refresh-token/msalApp.js +++ /dev/null @@ -1,174 +0,0 @@ -// Import dependencies -const express = require("express"); -const session = require('express-session'); -const cookieParser = require('cookie-parser'); -const msal = require('@azure/msal-node'); -require('dotenv').config(); - -const config = require('./config/customConfig.json'); - -const DiskCache = require('./adalCustomCache'); -const diskCache = new DiskCache(config.adalCacheLocation); - -const msalCachePlugin = require('./msalCachePlugin'); - -const REDIRECT_URI = config.redirectUri; - -const msalConfig = { - auth: { - clientId: config.clientId, - authority: `${config.authority}/${config.tenantInfo}`, - clientSecret: process.env.CLIENT_SECRET - }, - cache: { - cachePlugin: msalCachePlugin(config.msalCacheLocation) - }, - system: { - loggerOptions: { - loggerCallback(loglevel, message, containsPii) { - console.log(message); - }, - piiLoggingEnabled: false, - logLevel: msal.LogLevel.Verbose, - } - } -} - -// Initialize MSAL Node application object using authentication parameters -const cca = new msal.ConfidentialClientApplication(msalConfig); - -const cryptoProvider = new msal.CryptoProvider(); - -// Initialize express -const app = express(); - -app.use(cookieParser()); -app.use(express.json()); -app.use(express.urlencoded({ extended: false })); - -/** - * Using express-session middleware for persistent user session. Be sure to - * familiarize yourself with available options. Visit: https://www.npmjs.com/package/express-session - */ -app.use(session({ - secret: process.env.CLIENT_SECRET, // or any other random string of characters - resave: false, - saveUninitialized: false, - cookie: { - secure: false, // set this to true on production - } -})); - -app.get('/', async (req, res, next) => { - try { - // retrieve account - const account = await (await cca.getTokenCache()).getAccountByHomeId(req.session.account?.homeAccountId); - - if (!account) { - console.error('Account not found!'); - throw new msal.InteractionRequiredAuthError(); - } - - const tokenResponse = await cca.acquireTokenSilent({ - account: account, - scopes: ["user.read"], - }); - - res.json({ - message: 'successful silent flow token acquisition', - response: tokenResponse - }); - } catch (error) { - if (error instanceof msal.InteractionRequiredAuthError) { - /** - * If the silent token acquisition throws an interaction_required error, - * we catch it and attempt to find a refresh token for this user from ADAL cache. - * If no cached refresh token is found or if the refresh token is expired, - * we fallback to interactive flow via getAuthCodeUrl -> acquireTokenByCode. - */ - diskCache.find({ userId: req.cookies.userId }, async (error, data) => { - try { - if (error || !data || !data.length) throw new Error('Could not retrieve user cache'); - - /** - * You can add the /.default scope suffix to the resource to help migrate your apps - * from the v1.0 endpoint (ADAL) to the Microsoft identity platform (MSAL). - * For example, for the resource value of https://graph.microsoft.com, - * the equivalent scope value is https://graph.microsoft.com/.default - */ - const tokenResponse = await cca.acquireTokenByRefreshToken({ - refreshToken: data[0].refreshToken, - scopes: ['https://graph.microsoft.com/.default'], - forceCache: true, - }); - - req.session.account = tokenResponse.account; - - /** - * Once you successfully acquire an access token using a refresh token, - * we recommend to clear the ADAL cache for this user. - */ - diskCache.remove(data, (error, data) => { - if (error) return next(error); - - res.json({ - message: 'successful refresh token flow token acquisition', - response: tokenResponse - }); - }) - } catch (error) { - // create a random string of characters against csrf - req.session.state = cryptoProvider.createNewGuid(); - - // Construct a request object for auth code url - const authCodeUrlParameters = { - scopes: ["user.read"], - responseMode: 'form_post', - redirectUri: REDIRECT_URI, - state: req.session.state, - }; - - try { - // Request auth code url, then redirect - const authCodeUrl = await cca.getAuthCodeUrl(authCodeUrlParameters); - res.redirect(authCodeUrl); - } catch (error) { - next(error); - } - } - }); - } else { - next(error); - } - } -}); - -app.post('/redirect', async (req, res, next) => { - if (req.body.state) { - if (req.session.state === req.body.state) { - try { - // Exchange the auth code for tokens - const tokenResponse = await cca.acquireTokenByCode({ - code: req.body.code, - scopes: ["user.read"], - redirectUri: REDIRECT_URI, - }) - - req.session.account = tokenResponse.account; - - res.json({ - message: 'successful code flow token acquisition', - response: tokenResponse - }); - } catch (error) { - next(error); - } - } else { - next(new Error('state does not match')); - } - } else { - next(new Error('state not found')); - } -}); - -app.listen(3000, () => console.log(`listening on port 3000!`)); diff --git a/samples/msal-node-samples/refresh-token/msalCachePlugin.js b/samples/msal-node-samples/refresh-token/msalCachePlugin.js deleted file mode 100644 index 5cadbd79e3..0000000000 --- a/samples/msal-node-samples/refresh-token/msalCachePlugin.js +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. - */ -const fs = require('fs'); - -/** -* Cache Plugin configuration -*/ -module.exports = function (cacheLocation) { - const beforeCacheAccess = (cacheContext) => { - return new Promise((resolve, reject) => { - if (fs.existsSync(cacheLocation)) { - fs.readFile(cacheLocation, "utf-8", (error, data) => { - if (error) { - reject(); - } else { - cacheContext.tokenCache.deserialize(data); - resolve(); - } - }); - } else { - fs.writeFile(cacheLocation, cacheContext.tokenCache.serialize(), (error) => { - if (error) { - reject(); - } - }); - } - }); - } - - const afterCacheAccess = (cacheContext) => { - return new Promise((resolve, reject) => { - if (cacheContext.cacheHasChanged) { - fs.writeFile(cacheLocation, cacheContext.tokenCache.serialize(), (error) => { - if (error) { - reject(error); - } - resolve(); - }); - } else { - resolve(); - } - }); - }; - - - return { - beforeCacheAccess, - afterCacheAccess - } -} diff --git a/samples/msal-node-samples/refresh-token/package.json b/samples/msal-node-samples/refresh-token/package.json deleted file mode 100644 index a55745d36e..0000000000 --- a/samples/msal-node-samples/refresh-token/package.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "refresh-token", - "version": "1.0.0", - "description": "sample app for migrating from adal-node to msal-node", - "private": true, - "scripts": { - "start:msal": "node ./msalApp.js", - "start:adal": "node ./adalApp.js", - "build:package": "cd ../../../lib/msal-common && npm run build && cd ../msal-node && npm run build" - }, - "author": "Microsoft", - "license": "MIT", - "dependencies": { - "@azure/msal-node": "^3.0.0", - "adal-node": "^0.2.3", - "cookie-parser": "^1.4.6", - "dotenv": "^16.5.0", - "express": "^4.20.0", - "express-session": "^1.17.2", - "underscore": "^1.13.3" - }, - "devDependencies": { - } -}