Using Azure/Entra Authentication in React Js with Msal Library
Simplified MSal Authentication in React js.

Install the required libraries
pnpm install @azure/msal-react @azure/msal-browser
Create config file to keep all config
auth/msal-config.ts
import { LogLevel, type Configuration, type PopupRequest, type SilentRequest } from "@azure/msal-browser";
import appConfig from "../app-config";
export const msalConfig: Configuration = {
auth: {
clientId: "your_client_id",
authority: "https://login.microsoftonline.com/{your_tenant_id}",
redirectUri: appConfig.appUrl,
},
cache: {
cacheLocation: "localStorage",
storeAuthStateInCookie: false,
},
system: {
loggerOptions: {
logLevel: LogLevel.Info,
},
},
// add more options if needed
};
export const appScopes = ["App Scopes"];
auth/useMsalAuth.ts
import { useIsAuthenticated, useMsal } from "@azure/msal-react";
import { InteractionRequiredAuthError } from "@azure/msal-browser";
import { appScopes } from "./msal-config";
export default function useMsalAuth() {
const { instance, accounts } = useMsal();
const isAuthenticated = useIsAuthenticated();
const HOME_ACCOUNT_ID = "homeAccountId";
const ACCOUNT_USERNAME = "accountUsername";
// Function to handle login
const handleLogin = async () => {
try {
const response = await instance.loginPopup({
scopes: appScopes,
});
if (response.account) {
instance.setActiveAccount(response.account);
localStorage.setItem(HOME_ACCOUNT_ID, response.account.homeAccountId); // save the homeAccountId in local storage
localStorage.setItem(ACCOUNT_USERNAME, response.account.username); // save the username in local storage
}
} catch (error) {
console.error(error);
}
};
// Function to handle logout
const handleLogout = async () => {
await instance.logoutPopup({
account: getAccount(),
});
localStorage.removeItem(HOME_ACCOUNT_ID);
localStorage.removeItem(ACCOUNT_USERNAME);
};
// Function to access token when making api calls
const getAccessToken = async (): Promise<string | null> => {
try {
const authenticationResult = await instance.acquireTokenSilent({
scopes: appScopes,
account: getAccount(),
});
return authenticationResult.accessToken;
} catch (error) {
if (error instanceof InteractionRequiredAuthError) {
// fallback to interaction when silent call fails
const authenticationResult = await instance.acquireTokenPopup({
scopes: appScopes,
account: getAccount(),
});
return authenticationResult.accessToken;
}
return null;
}
};
// function to get The active account
const getAccount = () => {
const homeAccountId = localStorage.getItem(HOME_ACCOUNT_ID);
const accountUsername = localStorage.getItem(ACCOUNT_USERNAME);
if (!homeAccountId || !accountUsername) {
return;
}
const account = accounts.find((a) => a.homeAccountId === homeAccountId && a.username === accountUsername);
return account;
};
// function to check user roles
const hasRole = (role: string): boolean => {
const account = getAccount();
if (!account) {
return false;
}
const roles = account.idTokenClaims?.roles || [];
return roles.includes(role);
};
return {
isAuthenticated,
handleLogin,
handleLogout,
getAccessToken,
getAccount,
hasRole,
};
}
Protect Routes
Now we can use this hook to protect routes.
import { useIsAuthenticated } from "@azure/msal-react";
import { Navigate } from "react-router-dom";
export const ProtectedRoute = ({ children }) => {
const { isAuthenticated } = useMsalAuth();
if (!isAuthenticated) {
return <Navigate to="/" />;
}
return children;
};
use handleLogin, handleLogout, getAccessToken for login, logout and get the access token to make api calls to backend.
const { handleLogin, handleLogout, getAccessToken } = useMsalAuth();
use getAccount, hasRole to check user info and user roles
const { getAccount, hasRole } = useMsalAuth();