Tutorial: Sign in users and phone call the Microsoft Graph API from a React unmarried-page app (SPA) using auth code flow

In this tutorial, you build a React single-page awarding (SPA) that signs in users and calls Microsoft Graph by using the authorization code flow with PKCE. The SPA y'all build uses the Microsoft Authentication Library (MSAL) for React.

In this tutorial:

  • Create a React project with npm
  • Register the application in the Azure portal
  • Add together code to support user sign-in and sign-out
  • Add together code to call Microsoft Graph API
  • Exam the app

MSAL React supports the authorization code menses in the browser instead of the implicit grant menses. MSAL React does Non support the implicit flow.

Prerequisites

  • Node.js for running a local webserver
  • Visual Studio Code or some other code editor

How the tutorial app works

Diagram showing the authorization code flow in a single-page application

The application you create in this tutorial enables a React SPA to query the Microsoft Graph API by acquiring security tokens from the the Microsoft identity platform. Information technology uses the Microsoft Authentication Library (MSAL) for React, a wrapper of the MSAL.js v2 library. MSAL React enables React xvi+ applications to authenticate enterprise users by using Azure Active Directory (Azure AD), and also users with Microsoft accounts and social identities like Facebook, Google, and LinkedIn. The library as well enables applications to get access to Microsoft deject services and Microsoft Graph.

In this scenario, after a user signs in, an access token is requested and added to HTTP requests in the dominance header. Token acquisition and renewal are handled by the Microsoft Authentication Library for React (MSAL React).

Libraries

This tutorial uses the following libraries:

Library Description
MSAL React Microsoft Hallmark Library for JavaScript React Wrapper
MSAL Browser Microsoft Authentication Library for JavaScript v2 browser packet

Go the completed code sample

Adopt to download this tutorial's completed sample project instead? To run the project by using a local web server, such as Node.js, clone the ms-identity-javascript-react-spa repository:

git clone https://github.com/Azure-Samples/ms-identity-javascript-react-spa

Then, to configure the lawmaking sample earlier you lot execute information technology, skip to the configuration step.

To go on with the tutorial and build the awarding yourself, move on to the side by side department, Prerequisites.

Create your project

Once you lot have Node.js installed, open a concluding window so run the following commands:

              npx create-react-app msal-react-tutorial # Create a new React app cd msal-react-tutorial # Alter to the app directory npm install @azure/msal-browser @azure/msal-react # Install the MSAL packages npm install react-bootstrap bootstrap # Install Bootstrap for styling                          

Yous have now bootstrapped a pocket-sized React project using Create React App. This will be the starting indicate the residue of this tutorial will build on. If you would like to see the changes to your app as yous are working through this tutorial you can run the following command:

              npm starting time                          

A browser window should be opened to your app automatically. If information technology does not, open up your browser and navigate to http://localhost:3000. Each time you lot save a file with updated code the folio will reload to reflect the changes.

Register your application

Follow the steps in Single-folio application: App registration to create an app registration for your SPA by using the Azure portal.

In the Redirect URI: MSAL.js two.0 with auth code menstruum step, enter http://localhost:3000, the default location where create-react-app will serve your application.

Configure your JavaScript SPA

  1. Create a file named authConfig.js in the src folder to comprise your configuration parameters for authentication, so add the following code:

                      export const msalConfig = {   auth: {     clientId: "Enter_the_Application_Id_Here",     authorization: "Enter_the_Cloud_Instance_Id_Here/Enter_the_Tenant_Info_Here", // This is a URL (e.thousand. https://login.microsoftonline.com/{your tenant ID})     redirectUri: "Enter_the_Redirect_Uri_Here",   },   cache: {     cacheLocation: "sessionStorage", // This configures where your cache will be stored     storeAuthStateInCookie: imitation, // Set up this to "true" if you are having issues on IE11 or Edge   } };  // Add together scopes here for ID token to be used at Microsoft identity platform endpoints. export const loginRequest = {  scopes: ["User.Read"] };  // Add together the endpoints here for Microsoft Graph API services yous'd like to use. export const graphConfig = {     graphMeEndpoint: "Enter_the_Graph_Endpoint_Here/v1.0/me" };                                  
  2. Change the values in the msalConfig section as described here:

    Value name About
    Enter_the_Application_Id_Here The Application (client) ID of the application y'all registered.
    Enter_the_Cloud_Instance_Id_Here The Azure deject instance in which your application is registered. For the main (or global) Azure deject, enter https://login.microsoftonline.com. For national clouds (for case, Communist china), you can find appropriate values in National clouds.
    Enter_the_Tenant_Info_Here Set up to ane of the following options: If your application supports accounts in this organizational directory, supersede this value with the directory (tenant) ID or tenant name (for example, contoso.microsoft.com). If your application supports accounts in any organizational directory, supercede this value with organizations. If your application supports accounts in any organizational directory and personal Microsoft accounts, supercede this value with common. To restrict back up to personal Microsoft accounts only, supersede this value with consumers.
    Enter_the_Redirect_Uri_Here Replace with http://localhost:3000.
    Enter_the_Graph_Endpoint_Here The instance of the Microsoft Graph API the awarding should communicate with. For the global Microsoft Graph API endpoint, replace both instances of this string with https://graph.microsoft.com. For endpoints in national cloud deployments, see National cloud deployments in the Microsoft Graph documentation.

    For more information about available configurable options, see Initialize client applications.

  3. Open up upwards the src/index.js file and add the following imports:

                      import "bootstrap/dist/css/bootstrap.min.css"; import { PublicClientApplication } from "@azure/msal-browser"; import { MsalProvider } from "@azure/msal-react"; import { msalConfig } from "./authConfig";                                  
  4. Underneath the imports in src/index.js create a PublicClientApplication example using the configuration from step 1.

                      const msalInstance = new PublicClientApplication(msalConfig);                                  
  5. Find the <App /> component in src/index.js and wrap information technology in the MsalProvider component. Your render function should look like this:

                      ReactDOM.render(     <React.StrictMode>         <MsalProvider instance={msalInstance}>             <App />         </MsalProvider>     </React.StrictMode>,     document.getElementById("root") );                                  

Sign in users

Create a folder in src chosen components and create a file inside this folder named SignInButton.jsx. Add the lawmaking from either of the following sections to invoke login using a pop-upwards window or a total-frame redirect:

Sign in using pop-ups

Add the following code to src/components/SignInButton.jsx to create a button component that will invoke a pop-up login when selected:

              import React from "react"; import { useMsal } from "@azure/msal-react"; import { loginRequest } from "../authConfig"; import Button from "react-bootstrap/Button";  office handleLogin(example) {     case.loginPopup(loginRequest).catch(due east => {         console.error(eastward);     }); }  /**  * Renders a push which, when selected, will open a popup for login  */ export const SignInButton = () => {     const { instance } = useMsal();      return (         <Button variant="secondary" className="ml-auto" onClick={() => handleLogin(instance)}>Sign in using Popup</Push>     ); }                          

Sign in using redirects

Add the following code to src/components/SignInButton.jsx to create a button component that will invoke a redirect login when selected:

              import React from "react"; import { useMsal } from "@azure/msal-react"; import { loginRequest } from "../authConfig"; import Button from "react-bootstrap/Push button";  role handleLogin(instance) {     instance.loginRedirect(loginRequest).grab(e => {         panel.error(e);     }); }  /**  * Renders a push which, when selected, will redirect the page to the login prompt  */ export const SignInButton = () => {     const { instance } = useMsal();      return (         <Button variant="secondary" className="ml-auto" onClick={() => handleLogin(instance)}>Sign in using Redirect</Button>     ); }                          

Add the sign-in button

  1. Create another file in the components folder named PageLayout.jsx and add the following code to create a navbar component that will comprise the sign-in button y'all just created:

                      import React from "react"; import Navbar from "react-bootstrap/Navbar"; import { useIsAuthenticated } from "@azure/msal-react"; import { SignInButton } from "./SignInButton";  /**  * Renders the navbar component with a sign-in push button if a user is not authenticated  */ export const PageLayout = (props) => {     const isAuthenticated = useIsAuthenticated();      return (         <>             <Navbar bg="master" variant="nighttime">                 <a className="navbar-brand" href="/">MSAL React Tutorial</a>                 { isAuthenticated ? <bridge>Signed In</span> : <SignInButton /> }             </Navbar>             <h5><center>Welcome to the Microsoft Authentication Library For React Tutorial</center></h5>             <br />             <br />             {props.children}         </>     ); };                                  
  2. Now open src/App.js and add supercede the existing content with the following code:

                      import React from "react"; import { PageLayout } from "./components/PageLayout";  function App() {   return (       <PageLayout>           <p>This is the main app content!</p>       </PageLayout>   ); }  export default App;                                  

Your app now has a sign-in push which is simply displayed for unauthenticated users!

When a user selects the Sign in using Popup or Sign in using Redirect push for the starting time time, the onClick handler calls loginPopup (or loginRedirect) to sign in the user. The loginPopup method opens a popular-up window with the Microsoft identity platform endpoint to prompt and validate the user'south credentials. Subsequently a successful sign-in, msal.js initiates the authorization lawmaking catamenia.

At this point, a PKCE-protected authorization lawmaking is sent to the CORS-protected token endpoint and is exchanged for tokens. An ID token, admission token, and refresh token are received by your application and processed by msal.js, and the information independent in the tokens is cached.

Sign users out

In src/components create a file named SignOutButton.jsx. Add together the code from either of the following sections to invoke logout using a pop-up window or a full-frame redirect:

Sign out using pop-ups

Add the following lawmaking to src/components/SignOutButton.jsx to create a button component that will invoke a pop-upwards logout when selected:

              import React from "react"; import { useMsal } from "@azure/msal-react"; import Button from "react-bootstrap/Button";  function handleLogout(example) {     example.logoutPopup().catch(e => {         console.error(e);     }); }  /**  * Renders a push which, when selected, will open a popup for logout  */ consign const SignOutButton = () => {     const { instance } = useMsal();      return (         <Push variant="secondary" className="ml-auto" onClick={() => handleLogout(instance)}>Sign out using Popup</Button>     ); }                          

Sign out using redirects

Add the post-obit code to src/components/SignOutButton.jsx to create a push button component that will invoke a redirect logout when selected:

              import React from "react"; import { useMsal } from "@azure/msal-react"; import Button from "react-bootstrap/Button";  function handleLogout(instance) {     instance.logoutRedirect().take hold of(e => {         console.fault(e);     }); }  /**  * Renders a push button which, when selected, will redirect the page to the logout prompt  */ export const SignOutButton = () => {     const { instance } = useMsal();      return (         <Button variant="secondary" className="ml-auto" onClick={() => handleLogout(instance)}>Sign out using Redirect</Button>     ); }                          

Add the sign-out button

Update your PageLayout component in src/components/PageLayout.jsx to render the new SignOutButton component for authenticated users. Your code should look like this:

              import React from "react"; import Navbar from "react-bootstrap/Navbar"; import { useIsAuthenticated } from "@azure/msal-react"; import { SignInButton } from "./SignInButton"; import { SignOutButton } from "./SignOutButton";  /**  * Renders the navbar component with a sign-in push if a user is not authenticated  */ export const PageLayout = (props) => {     const isAuthenticated = useIsAuthenticated();      render (         <>             <Navbar bg="primary" variant="night">                 <a className="navbar-brand" href="/">MSAL React Tutorial</a>                 { isAuthenticated ? <SignOutButton /> : <SignInButton /> }             </Navbar>             <h5><eye>Welcome to the Microsoft Authentication Library For React Tutorial</eye></h5>             <br />             <br />             {props.children}         </>     ); };                          

Conditionally return components

In society to render certain components simply for authenticated or unauthenticated users use the AuthenticateTemplate and/or UnauthenticatedTemplate as demonstrated below.

  1. Add the post-obit import to src/App.js:

                      import { AuthenticatedTemplate, UnauthenticatedTemplate } from "@azure/msal-react";                                  
  2. In social club to render certain components only for authenticated users update your App function in src/App.js with the following lawmaking:

                      part App() {     return (         <PageLayout>             <AuthenticatedTemplate>                 <p>Yous are signed in!</p>             </AuthenticatedTemplate>         </PageLayout>     ); }                                  
  3. To render certain components only for unauthenticated users, such equally a proffer to login, update your App office in src/App.js with the following code:

                      role App() {     return (         <PageLayout>             <AuthenticatedTemplate>                 <p>You are signed in!</p>             </AuthenticatedTemplate>             <UnauthenticatedTemplate>                 <p>You are not signed in! Please sign in.</p>             </UnauthenticatedTemplate>         </PageLayout>     ); }                                  

Acquire a token

  1. Earlier calling an API, such every bit Microsoft Graph, y'all'll need to learn an access token. Add a new component to src/App.js called ProfileContent with the following code:

                      role ProfileContent() {     const { instance, accounts, inProgress } = useMsal();     const [accessToken, setAccessToken] = useState(zilch);      const name = accounts[0] && accounts[0].name;      office RequestAccessToken() {         const asking = {             ...loginRequest,             account: accounts[0]         };          // Silently acquires an access token which is then attached to a request for Microsoft Graph data         example.acquireTokenSilent(request).then((response) => {             setAccessToken(response.accessToken);         }).take hold of((e) => {             instance.acquireTokenPopup(asking).and then((response) => {                 setAccessToken(response.accessToken);             });         });     }      render (         <>             <h5 className="card-title">Welcome {name}</h5>             {accessToken ?                  <p>Access Token Acquired!</p>                 :                 <Push variant="secondary" onClick={RequestAccessToken}>Request Access Token</Button>             }         </>     ); };                                  
  2. Update your imports in src/App.js to match the following:

                      import React, { useState } from "react"; import { PageLayout } from "./components/PageLayout"; import { AuthenticatedTemplate, UnauthenticatedTemplate, useMsal } from "@azure/msal-react"; import { loginRequest } from "./authConfig"; import Push button from "react-bootstrap/Push";                                  
  3. Finally, add your new ProfileContent component as a kid of the AuthenticatedTemplate in your App component in src/App.js. Your App component should await like this:

                      part App() {   return (       <PageLayout>           <AuthenticatedTemplate>               <ProfileContent />           </AuthenticatedTemplate>           <UnauthenticatedTemplate>               <p>Yous are non signed in! Delight sign in.</p>           </UnauthenticatedTemplate>       </PageLayout>   ); }                                  

The code above will render a push button for signed in users, allowing them to request an admission token for Microsoft Graph when the button is selected.

After a user signs in, your app shouldn't ask users to reauthenticate every time they demand to admission a protected resource (that is, to request a token). To prevent such reauthentication requests, call acquireTokenSilent which will first look for a cached, unexpired admission token so, if needed, apply the refresh token to obtain a new access token. There are some situations, however, where yous might need to force users to collaborate with the Microsoft identity platform. For example:

  • Users demand to re-enter their credentials because the session has expired.
  • The refresh token has expired.
  • Your application is requesting access to a resource and y'all need the user's consent.
  • Two-factor hallmark is required.

Calling acquireTokenPopup opens a pop-upwardly window (or acquireTokenRedirect redirects users to the Microsoft identity platform). In that window, users demand to interact past confirming their credentials, giving consent to the required resource, or completing the 2-factor authentication.

Annotation

If you're using Internet Explorer, nosotros recommend that you use the loginRedirect and acquireTokenRedirect methods due to a known outcome with Internet Explorer and pop-up windows.

Telephone call the Microsoft Graph API

  1. Create file named graph.js in the src folder and add the following lawmaking for making Residuum calls to the Microsoft Graph API:

                      import { graphConfig } from "./authConfig";  /**  * Attaches a given access token to a Microsoft Graph API call. Returns data about the user  */ export async function callMsGraph(accessToken) {     const headers = new Headers();     const bearer = `Bearer ${accessToken}`;      headers.append("Authorization", bearer);      const options = {         method: "GET",         headers: headers     };      return fetch(graphConfig.graphMeEndpoint, options)         .so(response => response.json())         .catch(fault => panel.log(error)); }                                  
  2. Next create a file named ProfileData.jsx in src/components and add the following code:

                      import React from "react";  /**  * Renders data virtually the user obtained from Microsoft Graph  */ export const ProfileData = (props) => {     render (         <div id="profile-div">             <p><potent>First Proper name: </strong> {props.graphData.givenName}</p>             <p><strong>Last Name: </strong> {props.graphData.surname}</p>             <p><strong>Email: </stiff> {props.graphData.userPrincipalName}</p>             <p><strong>Id: </stiff> {props.graphData.id}</p>         </div>     ); };                                  
  3. Next, open src/App.js and add these to the imports:

                      import { ProfileData } from "./components/ProfileData"; import { callMsGraph } from "./graph";                                  
  4. Finally, update your ProfileContent component in src/App.js to call Microsoft Graph and display the contour data afterwards acquiring the token. Your ProfileContent component should look like this:

                      office ProfileContent() {     const { case, accounts } = useMsal();     const [graphData, setGraphData] = useState(nada);      const name = accounts[0] && accounts[0].name;      role RequestProfileData() {         const request = {             ...loginRequest,             account: accounts[0]         };          // Silently acquires an access token which is then attached to a request for Microsoft Graph information         instance.acquireTokenSilent(request).then((response) => {             callMsGraph(response.accessToken).and then(response => setGraphData(response));         }).grab((e) => {             instance.acquireTokenPopup(request).and then((response) => {                 callMsGraph(response.accessToken).so(response => setGraphData(response));             });         });     }      return (         <>             <h5 className="card-title">Welcome {name}</h5>             {graphData ?                  <ProfileData graphData={graphData} />                 :                 <Button variant="secondary" onClick={RequestProfileData}>Asking Profile Data</Button>             }         </>     ); };                                  

In the changes made above, the callMSGraph() method is used to brand an HTTP GET request against a protected resources that requires a token. The asking so returns the content to the caller. This method adds the acquired token in the HTTP Potency header. In the sample application created in this tutorial, the protected resource is the Microsoft Graph API me endpoint which displays the signed-in user's profile data.

Test your application

You've completed creation of the application and are now ready to launch the web server and examination the app's functionality.

  1. Serve your app past running the following command from inside the root of your project binder:

                      npm start                                  
  2. A browser window should be opened to your app automatically. If it does not, open your browser and navigate to http://localhost:3000. You should see a page that looks like the one beneath.

    Web browser displaying sign-in dialog

  3. Select the sign-in button to sign in.

The commencement fourth dimension yous sign in to your awarding, yous're prompted to grant it access to your profile and sign you lot in:

Content dialog displayed in web browser

If you consent to the requested permissions, the spider web applications displays your name, signifying a successful login:

Results of a successful sign-in in the web browser

Call the Graph API

After you sign in, select See Contour to view the user profile data returned in the response from the telephone call to the Microsoft Graph API:

Profile information from Microsoft Graph displayed in the browser

More than information almost scopes and delegated permissions

The Microsoft Graph API requires the user.read scope to read a user's profile. Past default, this scope is automatically added in every awarding that's registered in the Azure portal. Other APIs for Microsoft Graph, as well as custom APIs for your dorsum-stop server, might crave boosted scopes. For instance, the Microsoft Graph API requires the Mail.Read telescopic in society to list the user's e-mail.

As you add together scopes, your users might exist prompted to provide additional consent for the added scopes.

Assist and back up

If yous demand help, desire to report an issue, or want to larn about your back up options, see Help and back up for developers.

Next steps

If yous'd like to swoop deeper into JavaScript unmarried-page application evolution on the Microsoft identity platform, meet our multi-role scenario series: