HenrikM
HenrikM

Reputation: 1

MSAL.ts page behind AuthenticatedTemplate flashes before user is redirected to login

We are using the MSAL library in a vite project with Typescript. The chosen IDP is Azure B2C.

In our msalConfig we are using this setting:

...,
cache: {
    cacheLocation: "localStorage",
  },

The following behaviour is displayed by the app when the user tries to access a page inside an <AuthenticatedTemplate/> block:

If the user does not have a session stored in local storage the user is immediately redirected to the page we display in the <UnauthenticatedTemplate/>, i.e. the "home" page of the app. This is expected.

If the user has an active session in the browser (we suspect that the user has an active access token in local storage) the user is granted access to the page without any flickers or redirects.

However, after an at this moment unknown amount of idle time the user is at first shown a glimpse of the page that is behind the <AuthenticatedTemplate/> block before the user is redirected to the login screen provided by Azure B2C.

We have tested with changing the cacheLocation to sessionStorage and this behaviour disappears suggesting that this glimpsing behaviour can be attributed to delays in accessing local storage.

Have any others experienced this before? Is there a way of blocking the user access to protected pages until we know that the user has a valid session with the B2C tenant?

We tried changing the cacheLocation setting to sessionStorage and it fixed the temporary access to protected pages. However this removes browser wide sessions.

We tried to use the inProgress value returned by the useMsal() hook. We introduced this block:

<AuthenticatedTemplate>
 {inProgress !== "startup" && <OURSECRETPAGES/>}
</AuthenticatedTemplate>

where <OURSECRETPAGES/> refers to the react router element serving the logged in pages in our app. This did not help fixing the problem.

Upvotes: 0

Views: 33

Answers (1)

Dasari Kamali
Dasari Kamali

Reputation: 3649

I created a Vite React app with TypeScript to prevent displaying protected content until the user is authenticated.

App.tsx :

import React, { useEffect, useState } from 'react';
import { AuthenticatedTemplate, UnauthenticatedTemplate, useMsal } from '@azure/msal-react';
import { config } from './Config';

const ProtectedContent: React.FC = () => {
  return <div>Welcome to the protected content!</div>;
};

const App: React.FC = () => {
  const { instance, inProgress, accounts } = useMsal();
  const [isAuthenticated, setIsAuthenticated] = useState<boolean>(false);

  useEffect(() => {
    if (accounts.length > 0) {
      setIsAuthenticated(true);
    } else {
      setIsAuthenticated(false);
    }
  }, [accounts]);

  return (
    <div className="App">
      <header className="App-header">
        <h1>MSAL React App with Vite</h1>

        <UnauthenticatedTemplate>
          <button
            onClick={() =>
              instance.loginPopup({
                scopes: config.scopes,
                prompt: 'login',
              }).catch(error => console.error('Login failed: ', error))
            }
          >
            Login
          </button>
          <div>Please log in to access protected content.</div>
        </UnauthenticatedTemplate>

        <AuthenticatedTemplate>
          {inProgress === "none" && isAuthenticated ? (
            <div>
              <button onClick={() => instance.logout()}>Logout</button>
              <ProtectedContent />
            </div>
          ) : (
            <div>Redirecting...</div>
          )}
        </AuthenticatedTemplate>
      </header>
    </div>
  );
};
export default App;

main.tsx :

import React from 'react';
import ReactDOM from 'react-dom/client';
import { PublicClientApplication } from '@azure/msal-browser';
import { MsalProvider } from '@azure/msal-react';
import App from './App';

const msalInstance = new PublicClientApplication({
  auth: {
    clientId: import.meta.env.VITE_APP_ID,
    redirectUri: import.meta.env.VITE_REDIRECT_URI,
    authority: import.meta.env.VITE_AUTHORITY,
    knownAuthorities: [import.meta.env.VITE_KNOWN_AUTHORITIES],
  },
  cache: {
    cacheLocation: 'LocalStorage', 
    storeAuthStateInCookie: true,
  },
});

const root = document.getElementById('root') as HTMLElement;
ReactDOM.createRoot(root).render(
  <React.StrictMode>
    <MsalProvider instance={msalInstance}>
      <App />
    </MsalProvider>
  </React.StrictMode>
);

Config.ts :

export const config = {
    appId: import.meta.env.VITE_APP_ID,
    redirectUri: import.meta.env.VITE_REDIRECT_URI,
    scopes: import.meta.env.VITE_SCOPES.split(','),
    authority: import.meta.env.VITE_AUTHORITY,
    knownAuthorities: [import.meta.env.VITE_KNOWN_AUTHORITIES],
  };

.env :

VITE_APP_ID=<appID>
VITE_REDIRECT_URI=http://localhost:5173
VITE_AUTHORITY=https://<tenantName>.b2clogin.com/<tenantName>.onmicrosoft.com/<policyName>
VITE_SCOPES=openid,offline_access
VITE_KNOWN_AUTHORITIES=https://<tenantName>.b2clogin.com/<tenantName>.onmicrosoft.com/<policyName>

I have added the below URL in the service principal authentication redirect URI under Mobile and desktop applications and enabled Allow public client flows as shown below.

http://localhost:5173

enter image description here

I have added the offline_access and openid scopes.

enter image description here

Output :

I ran the Vite Reactjs application and got the below page as I am an unauthenticated user. Then, I logged in to Azure ADB2C using the Login button.

enter image description here

After successfully logging in, I was able to view the authenticated content, as shown below.

enter image description here

Upvotes: 0

Related Questions