I used the MSAL quickstart for react – creating a single tenant app registration for a SPA. The react code worked with the pop up meaning a user could sign in and the pop up went away.
Now I need to move from single tenant to multi-tenant with the fewest changes possible so I understand how the changes are required for multi-tenant.
I created a new app registration, with the only change being the all Microsoft accounts including xbox etc. In my code, I change the msal.auth.authority from my single tenant to common.
The sign on works but the popup window itself shows the website instead of closing and my original web browser having the authentication.
How do I get the popup to close correctly? It worked with single tenant, just not multitenant.
export const msalConfig = {
auth: {
clientId: process.env.AZURE_CLIENT_ID,
authority: `https://login.microsoftonline.com/common`, // This is a URL (e.g. https://login.microsoftonline.com/{your tenant ID} or /common)
redirectUri: "http://localhost:1234",
},
cache: {
cacheLocation: "sessionStorage", // This configures where your cache will be stored
storeAuthStateInCookie: false, // Set this to "true" if you are having issues on IE11 or Edge
}
};
// Add scopes here for ID token to be used at Microsoft identity platform endpoints.
export const loginRequest = {
scopes: ["User.Read"]
};
// Add the endpoints here for Microsoft Graph API services you'd like to use.
export const graphConfig = {
graphMeEndpoint: "https://graph.microsoft.com/v1.0/me"
};
import React from "react";
import { useMsal } from "@azure/msal-react";
import { loginRequest } from "../lib/authConfig";
import Button from "react-bootstrap/Button";
function handleLogin(instance) {
instance.loginPopup(loginRequest).catch((e) => {
console.error(e);
});
}
/**
* Renders a button which, when selected, will open a popup for login
*/
export const SignInButton = () => {
const { instance } = useMsal();
return (
<div className="text-end">
<Button
type="button"
className="btn btn-primary"
onClick={() => handleLogin(instance)}
>
Sign in
</Button>
</div>
);
};
import { render } from "react-dom";
import { BlobStorage } from "./BlobStorage";
import React, { StrictMode} from "react";
import { getAppConfig } from "./lib/appConfiguration";
import { PublicClientApplication } from "@azure/msal-browser";
import {
MsalProvider,
AuthenticatedTemplate,
UnauthenticatedTemplate
} from "@azure/msal-react";
import { PageLayout } from "./components/page-layout";
import { msalConfig } from "./lib/authConfig";
import 'bootstrap/dist/css/bootstrap.min.css';
import Welcome from "./Welcome";
import {
reactPlugin,
appInsights,
initializeMonitor,
withAITracking,
} from "./lib/appMonitor";
const msalInstance = new PublicClientApplication(msalConfig);
global.appConfig = getAppConfig();
global.appMonitor = appInsights;
console.log(global.appConfig);
initializeMonitor(global.appConfig.REACT_APP_MICROSOFT_APPLICATION_INSIGHTS);
const InnerApp = () => {
return (
<div>
<PageLayout>
<AuthenticatedTemplate>
<BlobStorage appConfig={global.appConfig}/>
</AuthenticatedTemplate>
<UnauthenticatedTemplate>
<Welcome />
</UnauthenticatedTemplate>
</PageLayout>
</div>
);
};
const MonitoredInnerApp = withAITracking(
reactPlugin,
InnerApp,
"4tt"
);
const App = () => {
return (
<StrictMode>
<MsalProvider instance={msalInstance}>
<MonitoredInnerApp />
</MsalProvider>
</StrictMode>
);
};
render(<App />, document.getElementById("root"));
import React from "react";
import { Container, Row, Col} from "react-bootstrap";
import { SignInButton } from "./button-sign-in";
import { SignOutButton } from "./button-sign-out";
import { useIsAuthenticated } from "@azure/msal-react";
/**
* All content is publicly available.
*/
export const Header = () => {
const isAuthenticated = useIsAuthenticated();
return (
<>
<Container className="container-fluid bg-secondary text-white" fluid>
<Row className="align-items-center text-start">
<Col className="col-sm-1 gap-3 text-uppercase">4tt</Col>
<Col className="gap-3">All Azure</Col>
<Col className="text-end">
{isAuthenticated ? <SignOutButton /> : <SignInButton />}
</Col>
</Row>
</Container>
</>
);
};
partial package.json
"devDependencies": {
"eslint": "8.8.0",
"eslint-config-prettier": "8.3.0",
"eslint-plugin-import": "^2.25.4",
"eslint-plugin-jsx-a11y": "^6.5.1",
"eslint-plugin-react": "^7.28.0",
"eslint-plugin-react-hooks": "^4.3.0",
"os-browserify": "^0.3.0",
"parcel": "2.2.1",
"path-browserify": "^1.0.1",
"prettier": "2.5.1",
"process": "^0.11.10"
},
"dependencies": {
"@azure/msal-browser": "^2.27.0",
"@azure/msal-react": "^1.4.3",
"@microsoft/applicationinsights-react-js": "^3.3.3",
"@microsoft/applicationinsights-web": "^2.8.3",
"bootstrap": "^5.2.0-beta1",
"dotenv": "^16.0.1",
"react": "17.0.2",
"react-bootstrap": "^2.4.0",
"react-dom": "17.0.2"
},
2
Answers
This behaviour could be related to the usage of /common endpoint with multi-tenant app. Although /common endpoint must be used with multi-tenant apps, guest users will be redirected to their home tenant to sign in which could explain the redirection issue. Try to use your tenantId instead of the /common endpoint and see if that solves the problem. Also, one of the other common errors when using the MSAL with multi-tenant app is it misses the cache entry originally made through the /common endpoint, so make sure that subsequent calls for the signed users are made to the tenant’s endpoint not /common.
The issue happens because your router replaces the hash in the url – which is required by the library to authenticate in the pop up. If you are using only popup based logins, change the entry point to not hit your logic when you find hash in the url, for instance, if you are using react –
Replace this in index.js
with this