React Admin MSAL Authentication Provider
ra-auth-msal provides an authentication provider for React-Admin applications, integrating seamlessly with the Microsoft Authentication Library (MSAL) to handle user authentication via Azure Active Directory. The current stable version is 3.1.0, with minor and patch releases occurring as needed to address bugs and introduce small enhancements. Major version updates tend to align with breaking changes in its core dependencies, `@azure/msal-browser` or `react-admin`. Key differentiators include built-in support for various MSAL authentication flows (Authorization Code, Implicit Grant), automatic token refresh, capabilities to fetch access tokens for Microsoft Graph API calls, and the ability to leverage user roles and groups for permission management within React-Admin. It simplifies the setup of MSAL within a React-Admin context, providing a custom login page and an HTTP client helper for authorized requests.
Common errors
-
Msal-browser@3.0.0-beta.0: Uninitialized_public_client_application: PublicClientApplication must be initialized by calling initialize() asynchronously.
cause The `initialize()` method of `PublicClientApplication` was not called after instantiation, which is a new requirement in MSAL v3.fixCall `myMSALObj.initialize()` within a `useEffect` hook or similar asynchronous context before using the MSAL instance. -
Msal-browser@3.0.0-beta.0: Interaction_in_progress: Interaction is currently in progress. Please complete the current interaction before attempting another.
cause An MSAL interactive authentication flow (e.g., login, acquire token) was initiated while another was still active, leading to a race condition or conflict.fixImplement logic to check `msalInstance.getAccount()` or similar before initiating a new interactive call, or ensure only one interaction can occur at a time. The package's `msalAuthProvider` should handle this generally, but ensure no conflicting manual MSAL calls are made. -
Error: `authProvider` did not return a `redirectToLogin` method.
cause The `authProvider` returned by `msalAuthProvider` might not be correctly configured or is missing required methods expected by `react-admin`.fixEnsure `msalAuthProvider` is called with a valid `msalInstance` and any necessary configuration. Verify that `react-admin` and `ra-auth-msal` versions are compatible.
Warnings
- breaking Upgraded `@azure/msal-browser` to v3.x, which requires the `PublicClientApplication` instance to be initialized asynchronously by calling `msalInstance.initialize()`.
- breaking Upgraded `react-admin` to v5.x. This may introduce breaking changes from `react-admin` itself that need to be addressed in your application.
- gotcha The `Admin` component must be wrapped in a `BrowserRouter`. MSAL's hash-based routing strategy for redirects is incompatible with `HashRouter`.
- gotcha The `navigateToLoginRequestUrl` property in your MSAL configuration (`msalConfig.auth`) should be set to `false`. React-Admin handles this redirection logic, and enabling it in MSAL can lead to conflicts.
Install
-
npm install ra-auth-msal -
yarn add ra-auth-msal -
pnpm add ra-auth-msal
Imports
- msalAuthProvider
const { msalAuthProvider } = require('ra-auth-msal');import { msalAuthProvider } from 'ra-auth-msal'; - LoginPage
import LoginPage from 'ra-auth-msal/LoginPage';
import { LoginPage } from 'ra-auth-msal'; - msalHttpClient
const msalHttpClient = require('ra-auth-msal').msalHttpClient;import { msalHttpClient } from 'ra-auth-msal'; - PublicClientApplication
import PublicClientApplication from '@azure/msal-browser';
import { PublicClientApplication } from '@azure/msal-browser';
Quickstart
import React, { useEffect } from "react";
import { Admin, Resource } from 'react-admin';
import { BrowserRouter } from "react-router-dom";
import { PublicClientApplication } from "@azure/msal-browser";
import { LoginPage, msalAuthProvider } from "ra-auth-msal";
const msalConfig = {
auth: {
clientId: "12345678-1234-1234-1234-123456789012", // Replace with your Azure AD App (client) ID
authority: "https://login.microsoftonline.com/common",
redirectUri: "http://localhost:8080/auth-callback", // Ensure this matches your Azure AD redirect URI
navigateToLoginRequestUrl: false,
},
cache: {
cacheLocation: "sessionStorage",
storeAuthStateInCookie: false,
},
};
const dataProvider = {
getList: () => Promise.resolve({ data: [{ id: 1, title: 'Post 1' }], total: 1 }),
getOne: () => Promise.resolve({ data: { id: 1, title: 'Post 1' } }),
getMany: () => Promise.resolve({ data: [{ id: 1, title: 'Post 1' }] }),
getManyReference: () => Promise.resolve({ data: [{ id: 1, title: 'Post 1' }], total: 1 }),
update: () => Promise.resolve({ data: { id: 1, title: 'Post 1' } }),
updateMany: () => Promise.resolve({ data: [{ id: 1, title: 'Post 1' }] }),
create: () => Promise.resolve({ data: { id: 1, title: 'Post 1' } }),
delete: () => Promise.resolve({ data: { id: 1, title: 'Post 1' } }),
deleteMany: () => Promise.resolve({ data: [{ id: 1, title: 'Post 1' }] })
}; // Placeholder dataProvider
const myMSALObj = new PublicClientApplication(msalConfig);
const App = () => {
useEffect(() => {
myMSALObj.initialize();
}, []);
const authProvider = msalAuthProvider({
msalInstance: myMSALObj,
loginRequest: {
scopes: ["User.Read"]
},
// permissions: getPermissionsFromAccount
});
return (
<BrowserRouter>
<Admin
authProvider={authProvider}
dataProvider={dataProvider}
title="Example Admin"
loginPage={LoginPage}
>
<Resource name="posts" />
</Admin>
</BrowserRouter>
);
};
export default App;