mvertopoulos / vue-msal

Vue plugin for using Microsoft Authentication Library (MSAL)
MIT License
123 stars 66 forks source link

Setting up without vue-msal #51

Open OssiPesonen opened 3 years ago

OssiPesonen commented 3 years ago

It appears obvious that the maintainers of this repo have long abandoned it. It's been nearly 1.5 years since the last update, and Azure's MSAL version is already in 2.18.0.

I recently also tried to set up MSAL for a Vue.js. app and stumbled into this package, as well as the vue-msal-2 package, but had no luck in getting them to work. So, I went and installed the @azure/msal-browser (latest version) and set it up manually, which was relatively easy for an app running on Nuxt.js. You can do this as well. No need for a wrapper. I'll try and write down the steps I took for anyone who stumbles into this repo.

Steps to set up @azure/msal-browser

Initialize

First thing you need to do is initialize MSAL. You need to set up a configuration object and pass it to the msa.PublicClientApplication function. Note that these settings are for my use case, and I will refer you to the msal-browser package documentation to figure out your needs. My use case is I have an Azure AD B2C tenant and an application there for an SPA that uses a redirect method instead of a popup window.

The example below is a nuxt.js plugin I set up in the plugins folder (/plugins/msal.js) which injects the msal into your Nuxt application, making it available there. No need to copy paste the whole thing, just grab what you need here.

import * as msal from "@azure/msal-browser";

export default ({ app }, inject) => {
    const msalConfig = {
        auth: {
            clientId: process.env.OAUTH_CLIENT_ID,
            authority: `https://${process.env.AZURE_B2C_TENANT}.b2clogin.com/${process.env.AZURE_B2C_TENANT}.onmicrosoft.com/${process.env.AZURE_B2C_POLICY}`,
            knownAuthorities: [`${process.env.AZURE_B2C_TENANT}.b2clogin.com`],
            redirectUri: process.env.AZURE_B2C_REDIRECT_URI,
            navigateToLoginRequestUrl: false,
            postLogoutRedirectUri: process.env.AZURE_B2C_TENANT,
        },
        cache: {
            cacheLocation: 'localStorage',
            storeAuthStateInCookie: true,
        }
    }

    const msalInstance = new msal.PublicClientApplication(msalConfig);

   // This is for Nuxt but you can easily pass it to a Vue instance as well using a plugin
    inject('msal', msalInstance);
}

Set up a function to handle the redirect from Azure

I set up a helper function to be called on the sign in process page, which basically handles a redirect promise (if available), fetches the user accounts and makes a silent token request. MSAL holds the token in localStorage (or sessionStorage) so it doesn't have to make trips to the server if the token is still viable.

import { AuthenticationResult,PublicClientApplication } from '@azure/msal-browser';

export function handleLoginRedirect(msal: PublicClientApplication, clientId: string): Promise<AuthenticationResult> {
    return new Promise((resolve, reject) => {
        msal.handleRedirectPromise().then(() => {
            const accounts = msal.getAllAccounts();

            if (accounts.length > 0) {
                msal.setActiveAccount(accounts[0]);

                const request = {
                    scopes: ['openid', 'profile', clientId],
                    account: accounts[0],
                };

                msal.acquireTokenSilent(request).then(tokenResponse => {
                    resolve(tokenResponse);
                }).catch((e) => {
                    reject(e);
                });
            } else {
                reject(new Error('no accounts found'));
            }
        });
    });
}

Once you have a token you can redirect the user to some other page, or if it fails you can throw him back to the login page.

  handleLoginRedirect(app.$msal, this.$config.AZURE_B2C_OAUTH_CLIENT_ID).then(() => {
        return redirect('/dashboard');
    }).catch(async () => {
        await app.$msal.loginRedirect({ scopes: ['openid', 'profile'] });
    });

Auth middleware (optional)

You can set up a middleware for Nuxt.js to make sure there's a viable token in play before allowing users to route to some pages.

import { handleLoginRedirect } from '~/assets/functions/auth';
import { Middleware } from '@nuxt/types';

const authMiddleware: Middleware = ({ app. $config }) => {
    handleLoginRedirect(app.$msal, $config.AZURE_B2C_OAUTH_CLIENT_ID).catch(async () => {
        await app.$msal.loginRedirect({ scopes: ['openid', 'profile'] });
    });
};

export default authMiddleware;

The example above should try and fetch the token and simply ignore it's response, but in case there's no token or account, msal will throw an error and you can redirect the user to a login page.

I hope that helps and people won't waste time on this repo!

flufy3d commented 3 years ago

thanks I have the same issue

OssiPesonen commented 3 years ago

I updated the code above. I stumbled on an issue where the package was constantly fetching a new access token over the internet, with every page load. It appears you have to input your app Client ID into the scopes to get an access token. The msal library uses the access token to maintain token expiration in cache. Without the access token it's read as non-existant and a new token is fetched each time.

twofingerrightclick commented 2 years ago

@OssiPesonen Much Appreciated!

swissbuechi commented 2 years ago

Thank you very much, I will definitely try this out.

Would you like to rewrite it for nuxt.js 3?

Also you could create a PR with a sample (nuxt2 or nuxt3) in the official Microsoft repository: https://github.com/AzureAD/microsoft-authentication-library-for-js/tree/dev/samples/msal-browser-samples

Thanks!

bhu-gmg commented 1 year ago

@OssiPesonen thanks heaps! I am going to try this out today...

bhu-gmg commented 1 year ago

@OssiPesonen I've wired it up and it works great! Thanks heaps :)

jashif commented 5 months ago

Any example for nuxt