Tutorial: Create a React SPA for authentication in an external tenant
This tutorial is part 2 of a series that demonstrates building a React single-page application (securing privileged access (SPA)) and preparing it for authentication using the Microsoft Entra admin center. In Part 1 of this series, you registered an application and configured user flows in your external tenant. This tutorial demonstrates how to create a React SPA using npm
and create files needed for authentication and authorization.
In this tutorial;
- Create a React project in Visual Studio Code
- Install identity and bootstrap packages
- Configure the settings for the application
Prerequisites
- Tutorial: Prepare your external tenant to authenticate users in a React SPA.
- Although any integrated development environment (IDE) that supports React applications can be used, this tutorial uses Visual Studio Code.
- Node.js.
Create a React project
Open Visual Studio Code, select File > Open Folder.... Navigate to and select the location in which to create your project.
Open a new terminal by selecting Terminal > New Terminal.
Run the following commands to create a new React project with the name reactspalocal, change to the new directory and start the React project. A web browser opens with the address
http://localhost:3000/
by default. The browser remains open and rerenders for every saved change.npx create-react-app reactspalocal cd reactspalocal npm start
Create additional folders and files to achieve the following folder structure:
reactspalocal ├─── public │ └─── index.html └───src ├─── components │ └─── DataDisplay.jsx │ └─── NavigationBar.jsx │ └─── PageLayout.jsx └───styles │ └─── App.css │ └─── index.css └─── utils │ └─── claimUtils.js └── App.jsx └── authConfig.js └── index.js
Install app dependencies
Identity related npm packages must be installed in the project to enable user authentication. For project styling, Bootstrap is used.
In the Terminal bar, select the + icon to create a new terminal. A new terminal window opens enabling the other terminal to continue running in the background.
If necessary, navigate to reactspalocal and enter the following commands into the terminal to install the
msal
andbootstrap
packages.npm install @azure/msal-browser @azure/msal-react npm install react-bootstrap bootstrap
Create the authentication configuration file, authConfig.js
In the src folder, open authConfig.js and add the following code snippet:
/* * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. */ import { LogLevel } from '@azure/msal-browser'; /** * Configuration object to be passed to MSAL instance on creation. * For a full list of MSAL.js configuration parameters, visit: * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/configuration.md */ export const msalConfig = { auth: { clientId: 'Enter_the_Application_Id_Here', // This is the ONLY mandatory field that you need to supply. authority: 'https://Enter_the_Tenant_Subdomain_Here.ciamlogin.com/', // Replace the placeholder with your tenant subdomain redirectUri: '/', // Points to window.location.origin. You must register this URI on Azure Portal/App Registration. postLogoutRedirectUri: '/', // Indicates the page to navigate after logout. navigateToLoginRequestUrl: false, // If "true", will navigate back to the original request location before processing the auth code response. }, cache: { cacheLocation: 'sessionStorage', // Configures cache location. "sessionStorage" is more secure, but "localStorage" gives you SSO between tabs. storeAuthStateInCookie: false, // Set this to "true" if you are having issues on IE11 or Edge }, system: { loggerOptions: { loggerCallback: (level, message, containsPii) => { if (containsPii) { return; } switch (level) { case LogLevel.Error: console.error(message); return; case LogLevel.Info: console.info(message); return; case LogLevel.Verbose: console.debug(message); return; case LogLevel.Warning: console.warn(message); return; default: return; } }, }, }, }; /** * Scopes you add here will be prompted for user consent during sign-in. * By default, MSAL.js will add OIDC scopes (openid, profile, email) to any login request. * For more information about OIDC scopes, visit: * https://docs.microsoft.com/azure/active-directory/develop/v2-permissions-and-consent#openid-connect-scopes */ export const loginRequest = { scopes: [], }; /** * An optional silentRequest object can be used to achieve silent SSO * between applications by providing a "login_hint" property. */ // export const silentRequest = { // scopes: ["openid", "profile"], // loginHint: "example@domain.net" // };
Replace the following values with the values from the Azure portal:
- Find the
Enter_the_Application_Id_Here
value and replace it with the Application ID (clientId) of the app you registered in the Microsoft Entra admin center. - In Authority, find
Enter_the_Tenant_Subdomain_Here
and replace it with the subdomain of your tenant. For example, if your tenant primary domain iscontoso.onmicrosoft.com
, usecontoso
. If you don't have your tenant name, learn how to read your tenant details.
- Find the
Save the file.
Use custom URL domain (Optional)
Use a custom domain to fully brand the authentication URL. From a user perspective, users remain on your domain during the authentication process, rather than being redirected to ciamlogin.com domain name.
Use the following steps to use a custom domain:
Use the steps in Enable custom URL domains for apps in external tenants to enable custom URL domain for your external tenant.
In your authConfig.js file, locate then
auth
object, then:- Update the value of the
authority
property to https://Enter_the_Custom_Domain_Here/Enter_the_Tenant_ID_Here. ReplaceEnter_the_Custom_Domain_Here
with your custom URL domain andEnter_the_Tenant_ID_Here
with your tenant ID. If you don't have your tenant ID, learn how to read your tenant details. - Add
knownAuthorities
property with a value [Enter_the_Custom_Domain_Here].
- Update the value of the
After you make the changes to your authConfig.js file, if your custom URL domain is login.contoso.com, and your tenant ID is aaaabbbb-0000-cccc-1111-dddd2222eeee, then your file should look similar to the following snippet:
//...
const msalConfig = {
auth: {
authority: process.env.AUTHORITY || 'https://login.contoso.com/aaaabbbb-0000-cccc-1111-dddd2222eeee',
knownAuthorities: ["login.contoso.com"],
//Other properties
},
//...
};
Modify index.js to include the authentication provider
All parts of the app that require authentication must be wrapped in the MsalProvider
component. You instantiate a PublicClientApplication then pass it to MsalProvider
.
In the src folder, open index.js and replace the contents of the file with the following code snippet to use the
msal
packages and bootstrap styling:import React from 'react'; import ReactDOM from 'react-dom/client'; import App from './App'; import { PublicClientApplication, EventType } from '@azure/msal-browser'; import { msalConfig } from './authConfig'; import 'bootstrap/dist/css/bootstrap.min.css'; import './styles/index.css'; /** * MSAL should be instantiated outside of the component tree to prevent it from being re-instantiated on re-renders. * For more, visit: https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-react/docs/getting-started.md */ const msalInstance = new PublicClientApplication(msalConfig); // Default to using the first account if no account is active on page load if (!msalInstance.getActiveAccount() && msalInstance.getAllAccounts().length > 0) { // Account selection logic is app dependent. Adjust as needed for different use cases. msalInstance.setActiveAccount(msalInstance.getActiveAccount()[0]); } // Listen for sign-in event and set active account msalInstance.addEventCallback((event) => { if (event.eventType === EventType.LOGIN_SUCCESS && event.payload.account) { const account = event.payload.account; msalInstance.setActiveAccount(account); } }); const root = ReactDOM.createRoot(document.getElementById('root')); root.render( <App instance={msalInstance}/> );