skip to Main Content

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
    })
})

2

Answers


  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

    Login or Signup to reply.
  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);
    });
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search