0

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
    })
})
Krisna
  • 2,854
  • 2
  • 24
  • 66
  • can you check is everthing fine in the console msalConfig in the configuration file ? is credentials setuped correct on the request – Hakob Sargsyan May 23 '22 at 07:47
  • I followed the setup based on doc. I even asked package github issues: https://github.com/AzureAD/microsoft-authentication-library-for-js/issues/4818 but did not find proper answer – Krisna May 23 '22 at 08:18
  • okay , can you check and try to console.log(msalConfig) in the setup file , what will be consoled for this part ``process.env.NEXT_PUBLIC_MSAL_CLIENT_ID || '',`` , is your credentials correct in the console , just check it – Hakob Sargsyan May 23 '22 at 08:21
  • It is correct.. I tested it. I even put hard coded client id – Krisna May 23 '22 at 08:26
  • can you check please what is the result of ``const isAuthenticated = useIsAuthenticated();`` , import it like this `import { useIsAuthenticated} from '@azure/msal-react';` – Hakob Sargsyan May 23 '22 at 09:11
  • Try also this ``const { inProgress, instance, accounts } = useMsal(); if (inProgress === InteractionStatus.None && !isAuthenticated) { setTimeout(() => { console.log(accounts.length) }, 1500) }`` – Hakob Sargsyan May 23 '22 at 09:15

2 Answers2

0

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

Hakob Sargsyan
  • 1,294
  • 1
  • 9
  • 15
0

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);
});
Venipa
  • 23
  • 1
  • 1
  • 5