I'm trying to implement a login with redirect flow in my application using msal-browser 3.5.0, Vue 3 and TypeScript. While I don't think that this is a really niche requirement I can't seem to find a tutorial that explains this exact case in a way that works for me personally. Here is the version of my code where I think it is closest to being successful:
TheHeaderBar.vue
<template>
<button @click="SignInWithRedirect">Login</button>
<button @click="SignOutWithRedirect">Logout</button>
</template>
<script lang="ts">
import { PublicClientApplication, type AccountInfo } from '@azure/msal-browser';
import useAzureAuthenticationStore from '@/stores/azureAuthentication';
import AuthorizationEvents from '../events/AuthorizationEvents';
import router from '@/router';
export default {
name: 'HeaderBar',
data() {
const store = useAzureAuthenticationStore();
const msalConfig = store.getMsalConfig;
const msalInstance = new PublicClientApplication(msalConfig) as PublicClientApplication;
msalInstance.handleRedirectPromise().then(response => {
console.log("redirect resp ", response);
}).catch(err => {
console.error(err);
})
return {
msalInstance, store
};
},
methods: {
SignInWithRedirect() {
this.msalInstance.loginRedirect({
scopes: ['user.read']
});
},
async SignOutWithRedirect() {
this.msalInstance.logoutRedirect();
}
},
};
</script>
The promise seems to be handled in some way here as I always get the "redirect resp" console output. The response object is always null though.
The config is obtained from my Pinia store azureAuthentication.ts:
import { type AccountInfo } from '@azure/msal-browser';
import { defineStore } from 'pinia';
export const useAzureAuthenticationStore = defineStore('azureAuthentication', {
state: () => ({
msalConfig: {
auth: {
clientId: import.meta.env.VITE_AZURE_CLIENT_ID,
authority: import.meta.env.VITE_AZURE_CLIENT_AUTHORITY,
},
cache: {
cacheLocation: "localStorage"
}
}
}),
getters: {
getClientId: (state) => state.msalConfig.auth.clientId,
getMsalConfig: (state) => state.msalConfig,
getAccount: () => JSON.parse(localStorage.getItem("account") || "{}")
},
actions: {
setAccount(account: AccountInfo | undefined): void {
localStorage.setItem("account", JSON.stringify(account !== undefined ? account : "{}"));
},
isLoggedIn(): boolean {
return localStorage.getItem("account") != null && localStorage.getItem("account") != "{}";
}
},
});
export default useAzureAuthenticationStore;
Note that here I'm also trying to put my user information into localStorage to have it persist between page reloads and staying logged in while switching between subpages of my own SPA. Not sure if that is really needed though as I could imagine that this will be handled by MSAL given that it is implemented correctly. Any information on that will also be appreciated.
If I had to guess my problem is that I load my page, initialize MSAL, leave the page for the redirect, go on the page again and MSAL forgets that I just logged in because it is not the same instance anymore. Just a guess though since I don't really think I can keep the exact same Vue component instance between redirects. Thank you really much for reading and hopefully answering!