I am currently developing a Vue application with Pinia as the state manager. I have created two plugins - one for authentication and another to set up my API instance. The second plugin relies on the token obtained from the first plugin.
Upon analyzing the execution order, I noticed that the second plugin runs immediately while the first one is still waiting for the token retrieval. Both plugins are asynchronous functions. Is there a way to adjust this sequence?
Here is the code snippet for my authentication plugin:
export async function authenticationPlugin({ store }: PiniaPluginContext) {
console.log('starting authentication');
const msalInstance = store.msalInstance as PublicClientApplication;
try {
console.log('starting await for silent sso')
const { idToken } = await msalInstance.ssoSilent(store.msalRequest);
console.log('signed in using silent sso and fetched id token');
const account = msalInstance.getAllAccounts()[0];
msalInstance.setActiveAccount(account);
console.log('active account set');
store.idToken = idToken;
console.log('id token stored in store');
} catch (error) {
if (error instanceof InteractionRequiredAuthError) {
const { idToken } = await store.msalInstance.acquireTokenPopup(store.msalRequest);
store.idToken = idToken;
}
}
}
And here is the implementation of my API plugin:
export async function apiPlugin({ store }: PiniaPluginContext) {
console.log('starting api plugin');
const msalInstance = store.msalInstance as PublicClientApplication;
console.log('setting up subscription');
store.$subscribe((mutation, store) => {
// @ts-ignore
if (mutation.events.key === 'idToken') {
console.log('inside subscription');
store.api = new Api(new Configuration({
basePath: config.BASE_PATH,
// @ts-ignore
accessToken: mutation.events.newValue
}));
console.log('end of subscription');
}
});
const api = new Api(new Configuration({
basePath: config.BASE_PATH,
accessToken: store.idToken
}));
console.log('api instance made');
// @ts-ignore
api.axios.interceptors.request.use(async (config) => {
const tokenResponse = await msalInstance.acquireTokenSilent(store.msalRequest);
if (tokenResponse.expiresOn!.getTime() < new Date().getTime()) {
console.log('expire?');
await msalInstance.ssoSilent(store.msalRequest);
const { idToken } = await msalInstance.acquireTokenSilent(store.msalRequest);
config.headers.Authorization = `Bearer ${idToken}`;
}
return config;
});
console.log('interceptor set');
store.api = api;
console.log('api added to store');
}
However, when the component utilizing the API for making calls is rendered, the token seems to not be set in the API instance for some reason, even though the idToken has been successfully populated in the store. Any suggestions on how to proceed would be greatly appreciated.