npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@wra-gov/vue-msal

v0.1.3

Published

[![NPM Version](https://img.shields.io/npm/v/%40wra-gov%2Fvue-msal)](https://www.npmjs.com/package/@wra-gov/vue-msal)

Readme

Vue Msal

NPM Version

Vue wrapper around Microsoft's MSAL.js for browser library

Installation

You can install the library,

npm install @wra-gov/vue-msal --save

Usage

Msal Instance

To use msal, a msal instance must be created. Msal instances have need an auth configuration. The user must provide this auth configuration.

The auth and cache objects are important. Objects in system help with debugging and are not required.

import { LogLevel, PublicClientApplication } from "@azure/msal-browser";

// Config object to be passed to Msal on creation
export const msalConfig = {
  auth: {
    clientId: "", // Fill in
    authority: "", // Fill in
    redirectUri: "/", // Must be registered as a SPA redirectURI on your app registration
    postLogoutRedirectUri: "/" // Must be registered as a SPA redirectURI on your app registration
  },
  cache: {
    cacheLocation: "localStorage"
  },
  system: {
    loggerOptions: {
      loggerCallback: (
        level: LogLevel,
        message: string,
        containsPii: boolean
      ) => {
        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);

Registration

The instance must be registered in index.js / index.ts. The plugin must always be the first thing initialised; all other things must happen after msal has finished initialisation.

To use control routing, the VueNavigationClient must be registered to the application's router,

const navigationClient = new VueNavigationClient(router);
msalInstance.setNavigationClient(navigationClient);

msal should be initialised in a promise,

msalInstance.initialize().then(() => {
  // This is a standard account configuration. Account configs can vary with
  // what the application requires.
  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(router);
  // The msal plugin is registered with the msalInstance
  app.use(msalPlugin, msalInstance);
  app.use(Wra);
  router.isReady().then(() => {
    // Waiting for the router to be ready prevents race conditions when returning from a loginRedirect or acquireTokenRedirect
    app.mount("#app");
  });
});

Guards

@wra-gov/vue-msal uses the meta object for route authorisation.

Guarded routes should have meta.requiresAuth set to true,

const routes: Array<RouteRecordRaw> = [
  {
    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
  }
];

After the routes are created, the registerGuard function should be called,

// Example router
const router = createRouter({
  history: createWebHistory(),
  routes
});

registerGuard(router, msalInstance, loginRequest);

export default router;

Composables

There are 3 composables,

  • useIsAuthenticated
    • Checks if the user is part of the Entra ID tentant.
    • Returns a boolean.
  • useMsal
    • Provides the user`s account details and a msal instance to use.
    • Asynchronous composable, requires checking a inProgress ref.
  • useMsalAuthentication
    • Accepts a scope parameter.
    • Accepts a authentication method. Either,
      • Redirect based - this is the WRA`s recommended way as it supports test engines.
      • Popup based - not recommended as it requires users to assign permissions and casuses issues with test engines.
    • Provides the user`s account details, and a token for the requested scope.
    • Asynchronous composable, requires checking a inProgress ref.

useIsAuthenticated

<template>
  <div v-if="!isAuthenticated">
    Please sign-in to see your profile information.
  </div>
  <div v-else>
    <p class="my-4">You are signed in.</p>
    <wra-button @click="goToProfile">Request Profile Information </wra-button>
  </div>
</template>

<script setup lang="ts">
import { useIsAuthenticated } from "@wra-gov/vue-msal";

// Returns a boolean reference
// This boolean can change over time
const isAuthenticated = useIsAuthenticated();
</script>

useMsal

Accessing account information using useMsal,

<template>
  <span v-if="!!name">Name: {{ name }}</span>
</template>

<script setup lang="ts">
import { computed } from "vue";
import { useMsal } from "@wra-gov/vue-msal";

const { accounts } = useMsal();

const name = computed(() => {
  if (accounts.value.length > 0) {
    const name = accounts.value[0].name ?? "";
    // Optional: Only get first name
    /* if (name) {
      return name.split(" ")[0];
    } */
  }
  return "";
});
</script>

Using the msal instance for sign in and sign out functionality,

loginRequest is an object containing the scopes for the login,

// Add scopes that are requested for id token provided by MS Identity Platform.
export const loginRequest = {
  scopes: ["User.Read"]
};
<template>
  <wra-app-bar class="nav-bar" id="top-nav-bar">
    <router-link class="links" to="/">Home</router-link>
    <div class="flex-grow"></div>
    <template v-if="isAuthenticated">
      <wra-button v-on:click="logoutPopup">Logout Popup</wra-button>
      <wra-button v-on:click="logoutRedirect">Logout Redirect</wra-button>
    </template>
    <template v-else>
      <wra-button @click="loginPopup">Login Popup</wra-button>
      <wra-button @click="loginRedirect">Login Redirect</wra-button>
    </template>
  </wra-app-bar>
</template>

<script setup lang="ts">
import { useIsAuthenticated, useMsal } from "@wra-gov/vue-msal";
import { loginRequest } from "../authConfig";

const { instance } = useMsal();
const isAuthenticated = useIsAuthenticated();

const logoutPopup = () => {
  instance.logoutPopup({
    mainWindowRedirectUri: "/"
  });
};

const logoutRedirect = () => {
  instance.logoutRedirect();
};

const loginPopup = () => {
  instance.loginPopup(loginRequest);
};

const loginRedirect = () => {
  instance.loginRedirect(loginRequest);
};
</script>

Using the msal instance through useMsal to get access tokens.

I would recommend using useMsalAuthentication over this,

loginRequest is an object containing the scopes for the graph query,

// Add scopes that are requested for id token provided by MS Identity Platform.
export const loginRequest = {
  scopes: ["User.Read"]
};

graphConfig is an object that contains the graph URLs,

// 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"
};
<template>
  <div v-if="state.resolved">
    <p>Name: {{ state.data.displayName }}</p>
    <p>Title: {{ state.data.jobTitle }}</p>
    <p>Mail: {{ state.data.mail }}</p>
    <p>
      Phone: {{ state.data.businessPhones ? state.data.businessPhones[0] : "" }}
    </p>
    <p>Location: {{ state.data.officeLocation }}</p>
  </div>
  <div v-else><p>Getting state</p></div>
</template>

<script setup lang="ts">
import { useMsal } from "@wra-gov/vue-msal";
import {
  InteractionRequiredAuthError,
  InteractionStatus
} from "@azure/msal-browser";
import { reactive, onMounted, watch } from "vue";
import { loginRequest } from "../authConfig";
import { callMsGraph } from "../utils/MsGraphApiCall";
import UserInfo from "../utils/UserInfo";

const { instance, inProgress } = useMsal();

const state = reactive({
  resolved: false,
  data: {} as UserInfo
});

async function getGraphData() {
  const response = await instance
    .acquireTokenSilent({
      ...loginRequest
    })
    .catch(async (e) => {
      if (e instanceof InteractionRequiredAuthError) {
        await instance.acquireTokenRedirect(loginRequest);
      }
      throw e;
    });
  if (inProgress.value === InteractionStatus.None) {
    const graphData = await callMsGraph(response.accessToken);
    state.data = graphData;
    state.resolved = true;
    stopWatcher();
  }
}

onMounted(() => {
  getGraphData();
});

const stopWatcher = watch(inProgress, () => {
  if (!state.resolved) {
    getGraphData();
  }
});
</script>

useMsalAuthentication

To use the useMsalAuthentication, an interaction type and scope must be passed in.

Interaction types:

  • InteractionType.Popup
  • InteractionType.Redirect
// Add scopes that are requested for id token provided by MS Identity Platform.
export const loginRequest = {
  scopes: ["User.Read"]
};

graphConfig is an object that contains the graph URLs,

// 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"
};
<template>
  <div v-if="state.resolved">
    <p>Name: {{ state.data.displayName }}</p>
    <p>Title: {{ state.data.jobTitle }}</p>
    <p>Mail: {{ state.data.mail }}</p>
    <p>
      Phone: {{ state.data.businessPhones ? state.data.businessPhones[0] : "" }}
    </p>
    <p>Location: {{ state.data.officeLocation }}</p>
  </div>
</template>

<script setup lang="ts">
import { useMsalAuthentication } from "@wra-gov/vue-msal";
import { InteractionType } from "@azure/msal-browser";
import { reactive, watch } from "vue";
import { loginRequest } from "../authConfig";
import { callMsGraph } from "../utils/MsGraphApiCall";
import UserInfo from "../utils/UserInfo";

const { result, acquireToken } = useMsalAuthentication(
  InteractionType.Redirect,
  loginRequest
);

const state = reactive({
  resolved: false,
  data: {} as UserInfo
});

async function getGraphData() {
  if (result.value) {
    const graphData = await callMsGraph(result.value.accessToken).catch(() =>
      acquireToken()
    );
    state.data = graphData;
    state.resolved = true;
  }
}

getGraphData();

watch(result, () => {
  getGraphData();
});
</script>

Options API

All of the composables listed above can be used in options API. However, they have to be placed into a setup method. The setup method places it's returns into the data() method automatically.

<template>
  <div v-if="state.resolved">
    <p>Name: {{ state.data.displayName }}</p>
    <p>Title: {{ state.data.jobTitle }}</p>
    <p>Mail: {{ state.data.mail }}</p>
    <p>
      Phone: {{ state.data.businessPhones ? state.data.businessPhones[0] : "" }}
    </p>
    <p>Location: {{ state.data.officeLocation }}</p>
  </div>
</template>

<script>
import { useMsalAuthentication } from "@/composables/UseMsalAuthentication";
import { apiRequest } from "@/config/auth";
import { InteractionType } from "@azure/msal-browser";

export default {
  data() {
    return {
      state: {
        resolved: false,
        data: {}
      }
    };
  },
  setup() {
    const { acquireToken, result, error, inProgress } = useMsalAuthentication(
      InteractionType.Redirect,
      apiRequest
    );

    return {
      acquireToken,
      result,
      error,
      inProgress
    };
  },
  watch: {
    inProgress: async function (newValue) {
      if (newValue === false) {
        await this.getGraphData();
      }
    }
  },
  methods: {
    getGraphData() {
      if (result.value) {
        const graphData = await callMsGraph(result.value.accessToken).catch(() =>
          acquireToken()
        );
        this.state.data = graphData;
        this.state.resolved = true;
      }
    }
  }
};
</script>

Sample / Test

The test folder contains an sample project, containing a typical WRA project structure with Tailwind and the WRA component library.

  • main.ts setups up the MSAL plugins
  • authConfig.ts provides the PublicClientApplication that is used by main.ts to setup configuration and hooks.
  • router/router.ts sets up role guards.

To run the sample / tests, you must navigate into the test folder. The top level of the repo is for the plugin, not the sample.

cd test
npm install
npm run dev