Nuxt with MSAL Popup auth

Setting up your new project

  • npm init nuxt-app <project-name>

    • Note this will ALSO create a subfolder of <project-name>

    • The installation process will also take you through some basic setup questions

  •  

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.