title: Call Azure AD protected API from React
body: <p>I have a react web-app which needs to access an ASP.NET Core API hosted in Azure. Both apps are protected by Azure AD. I have registered the apps separately in Azure AD App registrations. I have exposed the API which gave me this scope: api://{api_azure_client_id}/user_impersonation - this scope allows both users and admins to consent. I registered the react app separately and gave it permission to access the exposed the API scope.</p>
  
  <p>I am using MSAL to acquire tokens. I can successfully sign but I don't know how to acquire the access_token to call the API. I am following the <a href="https://github.com/AzureAD/microsoft-authentication-library-for-js/tree/dev/samples/react-sample-app" rel="nofollow noreferrer">the azure ad samples for react here</a>. The decision to use hooks was inspired by <a href="https://github.com/AzureAD/microsoft-authentication-library-for-js/pull/1206/commits/f05dfaae8c9cea9d0e8f93be4ff14779014ad42d" rel="nofollow noreferrer">this pull request on the sample.</a></p>
  
  <p>MSAL config:</p>
  
  <pre><code>export const GRAPH_SCOPES = {
   OPENID: "openid",
   PROFILE: "profile",
   USER_READ: "User.Read",
   API_CALL: "api://{api_azure_client_id}/user_impersonation"
  };
  
         export const GRAPH_ENDPOINTS = {
          ME: "https://graph.microsoft.com/v1.0/me"
        };
  
     export const GRAPH_REQUESTS = {
       LOGIN: {
        scopes: [
          GRAPH_SCOPES.OPENID,
          GRAPH_SCOPES.PROFILE,
          GRAPH_SCOPES.USER_READ,
          GRAPH_SCOPES.API_CALL
        ]
      }
    };
  
      export const msalApp = new UserAgentApplication({
        auth: {
          clientId: "react_app_azure_client_id",
          authority: "https://login.microsoftonline.com/common",
          validateAuthority: true,
          postLogoutRedirectUri: "http://localhost:3000",
          navigateToLoginRequestUrl: false
        },
        cache: {
          cacheLocation: "localStorage",
          storeAuthStateInCookie: isIE()
        }
      });
  </code></pre>
  
  <p>useAuthProvider hook:</p>
  
  <pre><code>    import { useState, useEffect } from "react";
      import { msalApp, requiresInteraction, fetchMsGraph, isIE, GRAPH_ENDPOINTS, GRAPH_REQUESTS
             } from "./../utils/auth-util";
  
       // If you support IE, our recommendation is that you sign-in using Redirect APIs
      const useRedirectFlow = isIE();
      // const useRedirectFlow = true;
  
      export default function useAuthProvider() {
       const [account, setAccount] = useState(null);
       const [accessToken, setAccessToken] = useState(null);
       const [error, setError] = useState(null);
       const [graphProfile, setGraphProfile] = useState(null);
  
        useEffect(() =&gt; {
          async function doAuth() {
           msalApp.handleRedirectCallback(error =&gt; {
             if (error) {
        const errorMessage = error.errorMessage
          ? error.errorMessage
          : "Unable to acquire access token.";
        // setState works as long as navigateToLoginRequestUrl: false
        setError(errorMessage);
      }
    });
  
    const account = msalApp.getAccount();
  
    setAccount(account);
  
    if (account) {
      const tokenResponse = await acquireToken(
        GRAPH_REQUESTS.LOGIN,
        useRedirectFlow
      );
  
      if (tokenResponse) {
        setAccessToken(tokenResponse.accessToken);
        const graphProfile = await fetchMsGraph(
          GRAPH_ENDPOINTS.ME,
          tokenResponse.accessToken
        ).catch(() =&gt; {
          setError("Unable to fetch Graph profile.");
        });
  
        if (graphProfile) {
          setGraphProfile(graphProfile);
        }
      }
    }
  }
  
     doAuth();
     }, []);
  
       async function acquireToken(request, redirect) {
         return msalApp.acquireTokenSilent(request).catch(error =&gt; {
           // Call acquireTokenPopup (popup window) in case of acquireTokenSilent failure
           // due to consent or interaction required ONLY
           if (requiresInteraction(error.errorCode)) {
           return redirect ? msalApp.acquireTokenRedirect(request) : 
                  msalApp.acquireTokenPopup(request);
           } else {
            console.error("Non-interactive error:", error.errorCode);
          }
        });
      }
  
        async function onSignIn(redirect) {
         if (redirect) {
           return msalApp.loginRedirect(GRAPH_REQUESTS.LOGIN);
         }
  
  const loginResponse = await msalApp
    .loginPopup(GRAPH_REQUESTS.LOGIN)
    .catch(error =&gt; {
      setError(error.message);
    });
  
  if (loginResponse) {
    setAccount(loginResponse.account);
    setError(null);
  
    const tokenResponse = await acquireToken(GRAPH_REQUESTS.LOGIN).catch(
      error =&gt; {
        setError(error.message);
      }
    );
  
    if (tokenResponse) {
      setAccessToken(tokenResponse.accessToken);
      const graphProfile = await fetchMsGraph(
        GRAPH_ENDPOINTS.ME,
        tokenResponse.accessToken
      ).catch(() =&gt; {
        setError("Unable to fetch Graph profile.");
      });
  
          if (graphProfile) {
             setGraphProfile(graphProfile);
            }
          }
        }
      }
  
       function onSignOut() {
          return msalApp.logout();
       }
  
       return {
         account,
         accessToken,
         error,
         graphProfile,
         onSignIn: () =&gt; onSignIn(useRedirectFlow),
         onSignOut: () =&gt; onSignOut()
       };
      }
  </code></pre>
  
  <p>I created an httpService which is just a wrapper for axios. I am using this service to call the api and the configuration of the httpService is as follows and is where I need the access token. I tried below but I am getting hooks can only be called inside a function body.</p>
  
  <pre><code>import axios from "axios";
  import useAuthProvider from "./useAuthProvider";
  
     axios.interceptors.request.use(
       config =&gt; {
       const { accessToken } = useAuthProvider();
  
     if (accessToken) {
        config.headers["Authorization"] = "Bearer " + accessToken;
     }        
        return config;
   },
     error =&gt; {
       Promise.reject(error);
     }
    );
  
     export default {
        get: axios.get,
        post: axios.post,
        put: axios.put,
        delete: axios.delete
     };
  </code></pre>
  
  <p>If user is not logged in I want to display a component with a Sign-In button which the prompts a user for credentials. I am doing this in the App component and its working perfectly.</p>
  
  <p>App.js</p>
  
  <pre><code>   import React from "react";
     import useAuthProvider from "./services/useAuthProvider";
     import NavBar from "./components/navigation/navBar";
     import "./App.css";
     import Welcome from "./components/welcome";
  
     function App() {
      const { account, accessToken, onSignIn } = useAuthProvider();
  
      if (account === null)
        return &lt;Welcome authButtonMethod={onSignIn.bind(this)} /&gt;;
      return &lt;NavBar /&gt;;
    }
  
      export default App;
  </code></pre>
  
  <p>I can work with having the token in local storage then get it from there in the httpService. Based on my code above where can I access the token and save it in local storage?</p>