'React-Apollo msal-browser with msal-react wrapper does not get accounts
I am moving my package from react-adal to @azure/msal-react. In react-adal I can authorise and able to go my app. I am using same client_id and Tenant_id but seems like getAllAccounts() returns me empty array, it means no user found as a result I am not getting any token. I used exactly same what the doc says. I am not sure what I am making mistake.
Here is my setup
import { Configuration, PopupRequest, PublicClientApplication } from '@azure/msal-browser'
export const msalConfig: Configuration = {
auth: {
clientId: process.env.NEXT_PUBLIC_MSAL_CLIENT_ID || '',
redirectUri: process.env.NEXT_PUBLIC_MSAL_REDIRECT_URL,
authority: `https://login.microsoftonline.com/${process.env.NEXT_PUBLIC_MSAL_TENANT}`,
navigateToLoginRequestUrl: true,
},
cache: {
cacheLocation: 'localStorage', // This configures where your cache will be stored
storeAuthStateInCookie: false,
},
}
export const loginRequest: PopupRequest = {
scopes: ['User.Read'],
}
export const msalInstance = new PublicClientApplication(msalConfig)
const currentAccounts = msalInstance.getAllAccounts()
console.log({ currentAccounts }) // returns empty array
This is how I warp my app with MsalProvider
import { ApolloProvider } from '@apollo/client'
import { MsalProvider } from '@azure/msal-react'
import { defaultClient } from 'apollo'
import { msalInstance } from 'msal-auth-config' // import msalInstance from config
import type { AppProps } from 'next/app'
import React from 'react'
const App = ({ Component, pageProps }: AppProps): JSX.Element => {
return (
<MsalProvider instance={msalInstance}>
<ApolloProvider client={defaultClient}>
<App />
</ApolloProvider>
</MsalProvider>
)
}
export default App
Here I want to return token
const authLink = setContext((_operation, { headers }) => {
const accounts = msalInstance.getAllAccounts()
//console.log({ accounts, headers })
if (accounts.length > 0) {
msalInstance.setActiveAccount(accounts[0])
}
return msalInstance
.acquireTokenSilent(loginRequest)
.then((response) => {
console.log(response) // return undefined
return { headers: { ...headers, Authorization: `Bearer ${response.idToken}` } }
})
.catch((error) => {
if (error instanceof InteractionRequiredAuthError) {
return msalInstance.acquireTokenRedirect(loginRequest)
}
return
})
})
Solution 1:[1]
Have you try to make it like this
import { useState, useEffect } from "react";
import { useMsal } from "@azure/msal-react";
import { InteractionStatus } from "@azure/msal-browser";
const { instance, accounts, inProgress } = useMsal();
const [loading, setLoading] = useState(false);
const [apiData, setApiData] = useState(null);
useEffect(() => {
if (!loading && inProgress === InteractionStatus.None && accounts.length > 0) {
if (apiData) {
// Skip data refresh if already set - adjust logic for your specific use case
return;
}
const tokenRequest = {
account: accounts[0], // This is an example - Select account based on your app's requirements
scopes: ["User.Read"]
}
// Acquire an access token
instance.acquireTokenSilent(tokenRequest).then((response) => {
// Call your API with the access token and return the data you need to save in state
callApi(response.accessToken).then((data) => {
setApiData(data);
setLoading(false);
});
}).catch(async (e) => {
// Catch interaction_required errors and call interactive method to resolve
if (e instanceof InteractionRequiredAuthError) {
await instance.acquireTokenRedirect(tokenRequest);
}
throw e;
});
}
}, [inProgress, accounts, instance, loading, apiData]);
if (loading || inProgress === InteractionStatus.Login) {
// Render loading component
} else if (apiData) {
// Render content that depends on data from your API
}
Read more here
Solution 2:[2]
you are probably missing the handleRedirectPromise... once the redirect is done the promise should catch the account... if not try another aquireSilentToken to catch it in the promise below.
instance.handleRedirectPromise().then(resp => {
if (resp && resp.account) instance.setActiveAccount(resp.account);
});
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Hakob Sargsyan |
| Solution 2 | Venipa |
