In today's web development landscape, building secure and interactive Single Page Applications (SPAs) is a common requirement. Integrating with Azure Active Directory (Azure AD) for authentication and authorization provides a robust and scalable solution. This post will guide you through the process of building an SPA using MSAL.js (Microsoft Authentication Library for JavaScript) to seamlessly authenticate users with Azure AD.
MSAL.js is a JavaScript client-side SDK that enables web applications to authenticate users using Azure AD v2.0 endpoint and acquire tokens for accessing protected web APIs. It supports both the Authorization Code Flow with PKCE and the Implicit Flow (though Authorization Code Flow is recommended for modern applications).
Before diving into the code, you need to register your SPA in Azure AD. Follow these steps:
http://localhost:3000 for local development).You can integrate MSAL.js into your project by installing it via npm or yarn:
npm install @azure/msal-browser
or
yarn add @azure/msal-browser
Create a configuration object that MSAL.js will use to interact with Azure AD. This typically involves your client ID, authority, and redirect URIs.
const msalConfig = {
auth: {
clientId: "YOUR_AZURE_AD_APPLICATION_CLIENT_ID",
authority: "https://login.microsoftonline.com/YOUR_AZURE_AD_TENANT_ID",
redirectUri: "http://localhost:3000", // Your SPA's redirect URI
},
cache: {
cacheLocation: "sessionStorage", // Or "localStorage"
storeAuthStateInCookie: false,
}
};
const msalInstance = new PublicClientApplication(msalConfig);
Replace YOUR_AZURE_AD_APPLICATION_CLIENT_ID and YOUR_AZURE_AD_TENANT_ID with the values from your Azure AD app registration. The authority URL can be customized for different clouds (e.g., GCC, China). The redirectUri must match exactly what you configured in Azure AD.
MSAL.js provides methods to initiate the login and logout processes.
To prompt the user to sign in:
async function login() {
try {
await msalInstance.loginRedirect({
scopes: ["user.read"] // Example scope for Microsoft Graph
});
} catch (error) {
console.error("Login failed:", error);
}
}
The loginRedirect method redirects the user to the Azure AD login page. After successful authentication, Azure AD will redirect the user back to your specified redirectUri with an ID token and/or access token in the URL fragment.
To sign the user out:
function logout() {
msalInstance.logoutRedirect({
postLogoutRedirectUri: "/" // Redirect to the home page after logout
});
}
The logoutRedirect method redirects the user to the Azure AD logout endpoint and then back to your application.
Once a user is logged in, you can acquire tokens for protected resources.
async function acquireToken(scopes) {
const accounts = msalInstance.getAllAccounts();
if (accounts.length === 0) {
// User is not logged in
return null;
}
const request = {
scopes: scopes,
account: accounts[0]
};
try {
const silentResult = await msalInstance.acquireTokenSilent(request);
return silentResult.accessToken;
} catch (error) {
// If silent acquisition fails, prompt user to log in interactively
console.warn("Silent token acquisition failed. Attempting interactive acquisition.");
try {
const interactiveResult = await msalInstance.acquireTokenRedirect(request); // Or acquireTokenPopup
return interactiveResult.accessToken;
} catch (interactiveError) {
console.error("Interactive token acquisition failed:", interactiveError);
return null;
}
}
}
acquireTokenSilent attempts to get a token without user interaction. If it fails (e.g., token expired, no session), acquireTokenRedirect (or acquireTokenPopup) can be used to prompt the user interactively.
Here's a conceptual example of how you might use MSAL.js in a React component:
// Assume MSAL configuration and instance are set up elsewhere
function MySecureComponent() {
const [isAuthenticated, setIsAuthenticated] = React.useState(false);
const [userInfo, setUserInfo] = React.useState(null);
React.useEffect(() => {
const checkAuth = async () => {
const accounts = msalInstance.getAllAccounts();
if (accounts.length > 0) {
setIsAuthenticated(true);
setUserInfo(accounts[0]);
// Optionally fetch data using acquired token
try {
const token = await acquireToken(["user.read"]);
if (token) {
console.log("Access Token:", token);
// Use the token to call an API
}
} catch (error) {
console.error("Failed to get token for API:", error);
}
} else {
setIsAuthenticated(false);
setUserInfo(null);
}
};
checkAuth();
}, []);
const handleLogin = () => {
login(); // Call the login function defined earlier
};
const handleLogout = () => {
logout(); // Call the logout function defined earlier
};
return (
{isAuthenticated ? (
Welcome, {userInfo?.name || userInfo?.username}!
) : (
Please sign in to continue.
)}
);
}
MSAL.js simplifies the integration of Azure AD authentication into your SPAs, providing a secure and straightforward way to manage user identities and access protected resources. By following these steps and leveraging the capabilities of MSAL.js, you can build robust and secure single-page applications with confidence.
Remember to always consult the official MSAL.js documentation for the latest updates and advanced configurations.